diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 26aee49f..f78c3926 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -49,7 +49,7 @@ Add any other context about the problem here. **Your config.json file** ``` { - "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json", + "$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json", "__comment1__": "This is a simple configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.", "__comment2__": "See node_modules/meshcentral/sample-config-advanced.json for a more advanced example.", "settings": { diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0ff81520..f2e315ce 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: Question + url: https://github.com/Ylianst/MeshCentral/discussions + about: Ask a question in discussions. - name: Unofficial Discord Server url: https://discord.gg/8wHC6ASWAc about: Please ask here for support questions. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 0a0f20ae..00000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: Question -about: Create a question for community help -title: '' -labels: question -assignees: '' - ---- - -**Describe your issue** -A clear and concise description of what your issue is. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Server Software (please complete the following information):** - - OS: [e.g. Ubuntu] - - Virtualization: [e.g. Docker] - - Network: [e.g. LAN/WAN, reverse proxy, cloudflare, ssl offload, etc...] - - Version: [e.g. 1.0.43] - - Node: [e.g. 18.4.0] - -**Client Device (please complete the following information):** - - Device: [e.g. Laptop] - - OS: [e.g. Ubuntu] - - Network: [e.g. Local to Meshcentral, Remote over WAN] - - Browser: [e.g. Google Chrome] - - MeshCentralRouter Version: [if applicable] - -**Remote Device (please complete the following information):** - - Device: [e.g. Laptop] - - OS: [e.g. Windows 10 21H2] - - Network: [e.g. Local to Meshcentral, Remote over WAN] - - Current Core Version (if known): [**HINT**: Go to a device then `console` Tab then type `info`] - -**Your config.json file** -``` -{ - "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json", - "__comment1__": "This is a simple configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.", - "__comment2__": "See node_modules/meshcentral/sample-config-advanced.json for a more advanced example.", - "settings": { - "_cert": "myserver.mydomain.com", - "_WANonly": true, - "_LANonly": true, - "_sessionKey": "MyReallySecretPassword1", - "_port": 443, - "_aliasPort": 443, - "_redirPort": 80, - "_redirAliasPort": 80 - }, - "domains": { - "": { - "_title": "MyServer", - "_title2": "Servername", - "_minify": true, - "_newAccounts": true, - "_userNameIsEmail": true - } - }, - "_letsencrypt": { - "__comment__": "Requires NodeJS 8.x or better, Go to https://letsdebug.net/ first before trying Let's Encrypt.", - "email": "myemail@mydomain.com", - "names": "myserver.mydomain.com", - "production": false - } -} -``` diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c8b3dd93..d5a2c9f6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -26,7 +26,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -48,4 +48,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index f4bae68d..f2127064 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -14,8 +14,8 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.x - run: pip install --upgrade pip diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 40d5c7f1..e4bafe94 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,55 +1,67 @@ name: Docker on: + push: + branches: + - master release: types: [published] + env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} + jobs: check-token: runs-on: ubuntu-latest outputs: - token: ${{ steps.token.outputs.defined }} + token_defined: ${{ steps.token_check.outputs.token_defined }} steps: - - id: token + - name: Check token + id: token_check env: - MY_TOKEN: ${{ secrets.MY_TOKEN }} + MY_TOKEN: ${{ secrets.MY_TOKEN }} if: "${{ env.MY_TOKEN != '' }}" - run: echo "::set-output name=defined::true" + run: echo "token_defined=true" >> "$GITHUB_OUTPUT" build: name: Release runs-on: ubuntu-latest needs: [check-token] - if: needs.check-token.outputs.token == 'true' + if: needs.check-token.outputs.token_defined == 'true' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 + - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.MY_TOKEN }} + - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: context: . file: docker/Dockerfile + platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - build-args: | + build-args: | INCLUDE_MONGODBTOOLS=true PREINSTALL_LIBS=true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eef13cd0..acf16409 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,8 @@ on: push: branches: - master + paths: + - 'package.json' jobs: build: @@ -10,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Release diff --git a/.gitignore b/.gitignore index 31e27dc4..e2031237 100644 --- a/.gitignore +++ b/.gitignore @@ -10,12 +10,12 @@ [Aa]gents/meshcore.min.js [Pp]ublic/translations/ [Vv]iews/translations/ +[Ee]mails/translations/ [Pp]ublic/*-min.htm [Vv]iews/*-min.handlebars meshcentral.db meshcentral.db.json mesherrors.txt -package-lock.json bob.json .greenlockrc diff --git a/.vscode/settings.json b/.vscode/settings.json index 93c4d0d5..596995f8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -779,6 +779,7 @@ "tokenuserid", "tokenusername", "totalsize", + "TOTP", "tpass", "tpassword", "tpush", diff --git a/LICENSE b/LICENSE index cf8faf5a..85c3dcae 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017-2021 Intel Corporation + Copyright 2017-2025 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj index b4f4a7c6..f5b9d0de 100644 --- a/MeshCentralServer.njsproj +++ b/MeshCentralServer.njsproj @@ -241,7 +241,6 @@ - @@ -441,7 +440,6 @@ - @@ -596,12 +594,14 @@ + + @@ -718,6 +718,7 @@ + @@ -764,6 +765,7 @@ + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..57790a24 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,49 @@ +# Security Policy + +## Supported Versions + +Any version of MeshCentral 1.x.x is supported. + +| Version | Supported | +| ------- | ------------------ | +| 1.x.x | :white_check_mark: | +| < 1.0 | :x: | + +## Reporting a Vulnerability + +Please report any concerns or security issue to Ylian Saint-Hilaire (ylianst@gmail.com). If needed, use my PGP key below. + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.56 + +mQMuBF2gC4sRCAClFNvMCCVW3ego3UHBQ6LhSenJfaZYhvn8gaGuemSQxqTI6bla +BTAv3aMtQnvqlSuadMMegb+FO6hnaQMlGvpVA1qpkSzgrPS5HrBD3H33J2Nj3i93 +ZpDPpxdI0ehCj6IJPnl0GxGbpKIN8YpJUFl44wv1lMRFI1lgyb+dCoO60irYdNQB +PV85BI+DwPfOBFHunwR78nqMvpvsk9HaeHjEP7oXr952/7EazUowZsMlEfkYnw5S ++tLfpCoY3QWkektpJP40nMJSKQdV2NEuED99doA0X+7P1vsvFFFyMH69dnU2uSay +XCHpkAbntBy0BGmtF1RnTcOMv2V/LPXnlMdvAQCbmLQzNra3r163tcdRY0jSs+pZ +1L3w5tHNj2dzhfpa7wf/SIuds6QTr2LCN6miLoSVCRMMpT7d771b16GwQqWEXzN2 ++h7dYqrssHPOa8FSUrPerz0+0eFcbMSm5/L/4KXWXoQthURv8aMP9E0iVoUYaaKB +7U+5vFEZbpoOZyZmTAjXQMSNZCft0azA82Q+G85euyicWtMv48yNVzUhkdh+M2ud +ohkXX2Aor1TqpBJoIeWke7j9D+Bo+lu61zPRx5ed9teUeLJCwqNEjlE+6gre5kxF +PoreAtn59QYcBIpzQEWVMbNFlDAR4jMyqIoKCGfBPiRw2V+kunbzqiGQEglIFfOt +6sTN/+CJh0ei976VDmE0Z1kMN+CNLgIjIw8fl02V9QgAnHcpqtVUxR4dbGOhVDq5 +lWv+K75QQlWyXC2k+KboXcaCvH0WZEBACYzO0CfrZ5hP9BSkbj5usSUVGGHwEFAJ +t+/04KVY71fW281Ej5kGNaIKxeKsx6+hMo+UXb5ZM+6fANNNxs1cK95sTH6PjkyB +tsKxLoa3CV2v9mSE5JiKKt74R9nXVo7PXf6DizwAU2l30Lb6y6y0OdXdCCPAG8Ij +FrMgPu5MtjgsO5DnkZfUqDPWHhOgEPyOh3Ho+pvDhNYh5cm2eLQ8g5orzs2FHwbZ +DpAHwCdqrlcpBlKJ4W/MZdf1fg2PjqaTWm7ZFiGr91P0F6kltTLWbVKTjLdS0T+D +L7QnWWxpYW4gU2FpbnQtSGlsYWlyZSA8eWxpYW5zdEBnbWFpbC5jb20+iF4EExEI +AAYFAl2gC4sACgkQg7j/r4DH+kD/3gD+MRedlM53VzOtNOpS6mqDAxj1aWP90HN0 +AqO6zuCTyGgBAJlunLFKH8IUetmQOhiohB8HVhdm/q4lKRDV7sHdplDyuMwEXaAL +ixACAJSU/sCV87he4oZUKzg2/IGl3QoDSbTCOd04dE1IjPjjHbi8t9M7Qau55aM8 +ypFEsc7zMslL8Fc78EejrKmM3zsB/RU9XWFyrbQwRbaK6OHeEHC2E3AFaG0p09c6 +d0kZloHuWyEsm5a/3PpbIM1eP9IESJXWCc+bQQt6DxLKHLmkKMwB/icWMg8uMJlx +aady8TEq7LH5oFVKsglnwuN1nIkecrf77TVkEqTjIxS6TiOup6zOnioFNKLYBAH0 +WUnJEYFvx4OIXgQYEQgABgUCXaALiwAKCRCDuP+vgMf6QGFTAQCUj2gGwsFlN0eR +Wowv4eLcc3FwQ+lBElUctKg8vNFb0gD/ZWVWsWwKerNgNnf7RGD9mt8G2CKvdgGG +oZ2hPP2gU9w= +=roW4 +-----END PGP PUBLIC KEY BLOCK----- +``` diff --git a/agents/MeshAgentOSXPackager.zip b/agents/MeshAgentOSXPackager.zip index c4936a66..4248a4eb 100644 Binary files a/agents/MeshAgentOSXPackager.zip and b/agents/MeshAgentOSXPackager.zip differ diff --git a/agents/MeshCentralRouter.exe b/agents/MeshCentralRouter.exe index bdb2b890..828675dc 100644 Binary files a/agents/MeshCentralRouter.exe and b/agents/MeshCentralRouter.exe differ diff --git a/agents/MeshCmd.exe b/agents/MeshCmd.exe index 4def3c52..00b704aa 100644 Binary files a/agents/MeshCmd.exe and b/agents/MeshCmd.exe differ diff --git a/agents/MeshCmd64.exe b/agents/MeshCmd64.exe index bcc1e7f5..e4af314f 100644 Binary files a/agents/MeshCmd64.exe and b/agents/MeshCmd64.exe differ diff --git a/agents/MeshCmdARM64.exe b/agents/MeshCmdARM64.exe new file mode 100644 index 00000000..83f1079a Binary files /dev/null and b/agents/MeshCmdARM64.exe differ diff --git a/agents/MeshService.exe b/agents/MeshService.exe index 29491297..e3aec7ab 100644 Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe index e1786250..540fed64 100644 Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ diff --git a/agents/MeshServiceARM64.exe b/agents/MeshServiceARM64.exe new file mode 100644 index 00000000..ee191f79 Binary files /dev/null and b/agents/MeshServiceARM64.exe differ diff --git a/agents/agent-translations.json b/agents/agent-translations.json index be8da762..554c68e5 100644 --- a/agents/agent-translations.json +++ b/agents/agent-translations.json @@ -37,7 +37,7 @@ "meshName": "Skupinové jméno", "meshId": "Identifikátor skupiny", "serverId": "Identifikátor serveru", - "setup": "Založit", + "setup": "Nastavit", "update": "Aktualizace", "install": "Instalace", "uninstall": "Odinstalace", @@ -52,7 +52,7 @@ "zenity": "Zkuste nainstalovat / aktualizovat Zenity a spustit znovu", "status": [ "NENÍ INSTALOVÁN", - "BĚH", + "SPUŠTĚNO", "NEFUNGUJE" ], "statusDescription": "Aktuální stav agenta", @@ -651,5 +651,98 @@ ], "statusDescription": "Trenutni status agenta", "description": "Kliknite na dugmad ispod da instalirate ili deinstalirate ovaj softver za daljinsko upravljanje. Kada je instaliran, ovaj softver radi u pozadini, što omogućava da ovim računarom upravlja i kontroliše udaljeni administrator." + }, + "hu": { + "agent": "Agent", + "agentVersion": "Új verzió", + "group": "Eszköz csoport", + "url": "Kiszolgáló URL", + "meshName": "Csoport név", + "meshId": "Csoport azonosító", + "serverId": "Kiszolgáló azonosító", + "setup": "Beállítás", + "update": "Frissítés", + "install": "Telepítés", + "uninstall": "Eltávolítás", + "connect": "Kapcsolódás", + "disconnect": "Lekapcsolódás", + "cancel": "Mégse", + "close": "Bezár", + "pressok": "Press OK to disconnect", + "elevation": "A szoftver telepítéséhez/eltávolításához megnövelt jogosultságok szükségesek.", + "sudo": "Kérjük, próbálja meg újra a sudo használatával.", + "ctrlc": "A kilépéshez nyomja meg a Ctrl-C billentyűt.", + "commands": "A szöveges változatot a parancssorból futtathatja a következő parancs(okk)al", + "graphicalerror": "A telepítő grafikus verziója nem futtatható ezen a rendszeren.", + "zenity": "Próbálja meg telepíteni/frissíteni a Zenity-t, és indítsa újra", + "status": [ + "NINCS TELEPÍTVE", + "FUT", + "NEM FUT" + ], + "statusDescription": "Jelenlegi agent állapota", + "description": "Kattintson a Telepítés vagy Eltávolítás gombokra a Távfelügyeleti alkalmazás telepítéséhez vagy eltávolításához. Telepítés után ez az alkalmazás a háttérben fut, lehetővé téve, hogy a számítógépet egy távoli rendszergazda kezelje." + }, + "ca": { + "agent": "Agent", + "agentVersion": "Nova versió", + "group": "Grup de dispositius", + "url": "URL del servidor", + "meshName": "Nom del grup", + "meshId": "Identificador de grup", + "serverId": "Identificador del servidor", + "setup": "Configuració", + "update": "Actualització", + "install": "Instal·lar", + "uninstall": "Desinstal·la", + "connect": "Connecta't", + "disconnect": "Desconnecta", + "cancel": "Cancel · lar", + "close": "Tanca", + "pressok": "Premeu D'acord per desconnectar", + "elevation": "Es necessiten permisos elevats per instal·lar/desinstal·lar aquest programari.", + "sudo": "Si us plau, torna-ho a provar amb sudo.", + "ctrlc": "Premeu Ctrl-C per sortir.", + "commands": "Podeu executar la versió de text des de la línia d'ordres amb les següents ordres", + "graphicalerror": "La versió gràfica d'aquest instal·lador no pot executar-se en aquest sistema", + "zenity": "Proveu d'instal·lar/actualitzar Zenity i torneu a executar-lo", + "status": [ + "NO ESTÀ INSTAL · LAT", + "CÓRRER", + "NO CORRE" + ], + "statusDescription": "Estat actual de l'agent", + "description": "Feu clic als botons següents per instal·lar o desinstal·lar aquest programari de gestió remota. Quan s'instal·la, aquest programari s'executa en segon pla i permet que aquest ordinador sigui gestionat i controlat per un administrador remot." + }, + "uk": { + "agent": "Агент", + "agentVersion": "Нова Версія", + "group": "Група Пристроїв", + "url": "URL Сервера", + "meshName": "Ім'я Групи", + "meshId": "Ідентифікатор групи", + "serverId": "Ідентифікатор серверу", + "setup": "Налаштувати", + "update": "Оновлення", + "install": "Інсталювати", + "uninstall": "Видалити", + "connect": "Підключитися", + "disconnect": "Відключити", + "cancel": "Скасувати", + "close": "Закрити", + "pressok": "Натисніть OK, щоб від'єднатися", + "elevation": "Для інсталяції/деінсталяції цього програмного забезпечення потрібні підвищені дозволи.", + "sudo": "Будь ласка, спробуйте ще раз за допомогою sudo.", + "ctrlc": "Натисніть Ctrl-C, щоб вийти", + "commands": "Ви можете запустити текстову версію з командного рядка за допомогою таких команд", + "graphicalerror": "Графічна версія цього інсталятора не може працювати в цій системі", + "zenity": "Спробуйте встановити/оновити Zenity та запустіть наново", + "status": [ + "НЕ ВСТАНОВЛЕНО", + "ВИКОНУЄТЬСЯ", + "НЕ ПРАЦЮЄ" + ], + "statusDescription": "Поточний Статус Агента", + "description": "Клікнути кнопки нижче, щоб інсталювати або видалити це програмне забезпечення для віддаленого керування. Після інсталювання ця програма працює у фоновому режимі, що дозволяє віддаленому адміністратору керувати цим комп'ютером." } } \ No newline at end of file diff --git a/agents/compressModules-new.bat b/agents/compressModules-new.bat deleted file mode 100644 index 1b2e3d74..00000000 --- a/agents/compressModules-new.bat +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF -MD modules_meshcmd_min -MD modules_meshcore_min - -%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcmd.js -RENAME meshcmd.js.min meshcmd.min.js -%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcore.js -RENAME meshcore.js.min meshcore.min.js - -%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minifydir C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcore C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcore_min -%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minifydir C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcmd C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcmd_min diff --git a/agents/compressModules-old.bat b/agents/compressModules-old.bat deleted file mode 100644 index dd9d8444..00000000 --- a/agents/compressModules-old.bat +++ /dev/null @@ -1,20 +0,0 @@ -@ECHO OFF -MD modules_meshcmd_min -MD modules_meshcore_min -"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" compressalljs "modules_meshcore" "modules_meshcore_min" -"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" compressalljs "modules_meshcmd" "modules_meshcmd_min" -"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" meshcore.js -"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" meshcmd.js - -REM del meshcore.min.js -REM %LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcore.js -REM rename meshcore.js.min meshcore.min.js - -REM del meshcmd.min.js -REM %LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcmd.js -REM rename meshcmd.js.min meshcmd.min.js - -REM Minify the translations -%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify modules_meshcore\coretranslations.json -COPY modules_meshcore\coretranslations.json.min modules_meshcore_min\coretranslations.json -DEL modules_meshcore\coretranslations.json.min \ No newline at end of file diff --git a/agents/meshagent_aarch64 b/agents/meshagent_aarch64 index 7af8a134..f1e94db6 100644 Binary files a/agents/meshagent_aarch64 and b/agents/meshagent_aarch64 differ diff --git a/agents/meshagent_aarch64-cortex-a53 b/agents/meshagent_aarch64-cortex-a53 index 209f4c71..11cbfdbc 100644 Binary files a/agents/meshagent_aarch64-cortex-a53 and b/agents/meshagent_aarch64-cortex-a53 differ diff --git a/agents/meshagent_android.apk b/agents/meshagent_android.apk new file mode 100644 index 00000000..0b525a3b Binary files /dev/null and b/agents/meshagent_android.apk differ diff --git a/agents/meshagent_arm b/agents/meshagent_arm index d6bdfd98..7c857e5f 100644 Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ diff --git a/agents/meshagent_arm-linaro b/agents/meshagent_arm-linaro index fd9bd95a..61f20631 100644 Binary files a/agents/meshagent_arm-linaro and b/agents/meshagent_arm-linaro differ diff --git a/agents/meshagent_armhf b/agents/meshagent_armhf index e1ee8514..3a4f42dc 100644 Binary files a/agents/meshagent_armhf and b/agents/meshagent_armhf differ diff --git a/agents/meshagent_linux-armada370-hf b/agents/meshagent_linux-armada370-hf index 9e7f8d92..aaac5625 100644 Binary files a/agents/meshagent_linux-armada370-hf and b/agents/meshagent_linux-armada370-hf differ diff --git a/agents/meshagent_mips b/agents/meshagent_mips index fff4fbb3..4230b2e2 100644 Binary files a/agents/meshagent_mips and b/agents/meshagent_mips differ diff --git a/agents/meshagent_mips24kc b/agents/meshagent_mips24kc index 71f8f641..91198cbe 100644 Binary files a/agents/meshagent_mips24kc and b/agents/meshagent_mips24kc differ diff --git a/agents/meshagent_mipsel24kc b/agents/meshagent_mipsel24kc index 85d46a18..d759f438 100644 Binary files a/agents/meshagent_mipsel24kc and b/agents/meshagent_mipsel24kc differ diff --git a/agents/meshagent_openwrt_x86_64 b/agents/meshagent_openwrt_x86_64 index 0157801a..c81a13ed 100644 Binary files a/agents/meshagent_openwrt_x86_64 and b/agents/meshagent_openwrt_x86_64 differ diff --git a/agents/meshagent_pogo b/agents/meshagent_pogo index 4790f8a7..9ffbbff2 100644 Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ diff --git a/agents/meshagent_poky b/agents/meshagent_poky index e95e080b..ecbb530e 100644 Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ diff --git a/agents/meshagent_poky64 b/agents/meshagent_poky64 index cd04aeb9..0b260438 100644 Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ diff --git a/agents/meshagent_x86 b/agents/meshagent_x86 index a2604a22..33b5d9db 100644 Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ diff --git a/agents/meshagent_x86-64 b/agents/meshagent_x86-64 index 2a6d0bc1..0c3e00de 100644 Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ diff --git a/agents/meshagent_x86-64_nokvm b/agents/meshagent_x86-64_nokvm index c77127a4..3f865a61 100644 Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ diff --git a/agents/meshagent_x86_nokvm b/agents/meshagent_x86_nokvm index 09ecf029..6d924a05 100644 Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ diff --git a/agents/meshcmd.js b/agents/meshcmd.js index ac782e8c..1142c31a 100644 --- a/agents/meshcmd.js +++ b/agents/meshcmd.js @@ -588,7 +588,7 @@ function run(argv) { } amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } }); amtMei.getProvisioningMode(function (result) { if (result) { mestate.ProvisioningMode = result; } }); - amtMei.getEHBCState(function (result) { mestate.ehbc = ((result === true) || (typeof result == 'object') && (result.EHBC === true)); }); + amtMei.getEHBCState(function (result) { if (result) { mestate.ehbc = ((result === true) || (typeof result == 'object') && (result.EHBC === true)); } }); amtMei.getControlMode(function (result) { if (result) { mestate.controlmode = result; } }); amtMei.getMACAddresses(function (result) { if (result) { mestate.mac = result; } }); amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } }); diff --git a/agents/meshcore.js b/agents/meshcore.js index afebe454..5a7faaf1 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -295,8 +295,9 @@ if (process.platform == 'win32' && require('user-sessions').isRoot()) { // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value try { var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024); - try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (ex) { } - if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (ex) { } } + var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent')); + try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize'); } catch (ex) { } + if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize', actualSize); } catch (ex) { } } } catch (ex) { } // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode @@ -310,6 +311,16 @@ if (process.platform == 'win32' && require('user-sessions').isRoot()) { try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (ex) { } if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); } } catch (ex) { } + + // Check the Agent Uninstall MetaData for DisplayVersion and update if not the same and only on windows + if (process.platform == 'win32') { + try { + var writtenDisplayVersion = 0, actualDisplayVersion = process.versions.commitDate.toString(); + var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent')); + try { writtenDisplayVersion = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'DisplayVersion'); } catch (ex) { } + if (writtenDisplayVersion != actualDisplayVersion) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'DisplayVersion', actualDisplayVersion); } catch (ex) { } } + } catch (ex) { } + } } if (process.platform != 'win32') { @@ -622,7 +633,7 @@ if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require(' else { try { // Setup normal battery monitoring - if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered()) { + if (require('computer-identifiers').isBatteryPowered && require('computer-identifiers').isBatteryPowered()) { require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) { _battLevelChanged.self._currentBatteryLevel = val; _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val }); @@ -654,35 +665,40 @@ var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? // Get the operating system description string try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (ex) { } - // Setup logged in user monitoring (THIS IS BROKEN IN WIN7) +function onUserSessionChanged(user, locked) { + userSession.enumerateUsers().then(function (users) { + if (process.platform == 'linux') { + if (userSession._startTime == null) { + userSession._startTime = Date.now(); + userSession._count = users.length; + } + else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) { + userSession.removeAllListeners('changed'); + return; + } + } + + var u = [], a = users.Active; + if(meshCoreObj.lusers == null) { meshCoreObj.lusers = []; } + for (var i = 0; i < a.length; i++) { + var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username); + if (user && locked && (JSON.stringify(a[i]) === JSON.stringify(user))) { if (meshCoreObj.lusers.indexOf(un) == -1) { meshCoreObj.lusers.push(un); } } + else if (user && !locked && (JSON.stringify(a[i]) === JSON.stringify(user))) { meshCoreObj.lusers.splice(meshCoreObj.lusers.indexOf(un), 1); } + if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once. + } + meshCoreObj.lusers = meshCoreObj.lusers; + meshCoreObj.users = u; + meshCoreObjChanged(); + }); +} + try { var userSession = require('user-sessions'); - userSession.on('changed', function onUserSessionChanged() { - userSession.enumerateUsers().then(function (users) { - if (process.platform == 'linux') { - if (userSession._startTime == null) { - userSession._startTime = Date.now(); - userSession._count = users.length; - } - else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) { - userSession.removeAllListeners('changed'); - return; - } - } - - var u = [], a = users.Active; - for (var i = 0; i < a.length; i++) { - var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username); - if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once. - } - meshCoreObj.users = u; - meshCoreObjChanged(); - }); - }); + userSession.on('changed', function () { onUserSessionChanged(null, false); }); userSession.emit('changed'); - //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); }); - //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); }); + userSession.on('locked', function (user) { if(user != undefined && user != null) { onUserSessionChanged(user, true); } }); + userSession.on('unlocked', function (user) { if(user != undefined && user != null) { onUserSessionChanged(user, false); } }); } catch (ex) { } var meshServerConnectionState = 0; @@ -1159,6 +1175,8 @@ function handleServerCommand(data) { tunnel.soptions = data.soptions; tunnel.consentTimeout = (tunnel.soptions && tunnel.soptions.consentTimeout) ? tunnel.soptions.consentTimeout : 30; tunnel.consentAutoAccept = (tunnel.soptions && (tunnel.soptions.consentAutoAccept === true)); + tunnel.consentAutoAcceptIfNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfNoUser === true)); + tunnel.oldStyle = (tunnel.soptions && tunnel.soptions.oldStyle) ? tunnel.soptions.oldStyle : false; tunnel.tcpaddr = data.tcpaddr; tunnel.tcpport = data.tcpport; tunnel.udpaddr = data.udpaddr; @@ -1215,8 +1233,11 @@ function handleServerCommand(data) { ipr.message = data.msg; ipr.username = data.username; if (data.realname && (data.realname != '')) { ipr.username = data.realname; } + ipr.timeout = (typeof data.timeout === 'number' ? data.timeout : 120000); global._clientmessage = ipr.then(function (img) { - this.messagebox = require('win-dialog').create(this.title, this.message, this.username, { timeout: 120000, b64Image: img.split(',').pop(), background: color_options.background, foreground: color_options.foreground }); + var options = { b64Image: img.split(',').pop(), background: color_options.background, foreground: color_options.foreground } + if (this.timeout != 0) { options.timeout = this.timeout; } + this.messagebox = require('win-dialog').create(this.title, this.message, this.username, options); this.__childPromise.addMessage = this.messagebox.addMessage.bind(this.messagebox); return (this.messagebox); }); @@ -1247,6 +1268,9 @@ function handleServerCommand(data) { // Requestion details information about a process if (data.pid) { var info = {}; // TODO: Replace with real data. Feel free not to give all values if not available. + try { + info = processManager.getProcessInfo(data.pid); + }catch(e){ } /* info.processUser = "User"; // String info.processDomain = "Domain"; // String @@ -1283,6 +1307,41 @@ function handleServerCommand(data) { } break; } + case 'service': { + // return information about the service + try { + var service = require('service-manager').manager.getService(data.serviceName); + if (service != null) { + var reply = { + name: (service.name ? service.name : ''), + status: (service.status ? service.status : ''), + startType: (service.startType ? service.startType : ''), + failureActions: (service.failureActions ? service.failureActions : ''), + installedDate: (service.installedDate ? service.installedDate : ''), + installedBy: (service.installedBy ? service.installedBy : '') , + user: (service.user ? service.user : '') + }; + if(reply.installedBy.indexOf('S-1-5') != -1) { + var cmd = "(Get-WmiObject -Class win32_userAccount -Filter \"SID='"+service.installedBy+"'\").Caption"; + var replydata = ""; + var pws = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {}); + pws.descriptorMetadata = 'UserSIDPowerShell'; + pws.stdout.on('data', function (c) { replydata += c.toString(); }); + pws.stderr.on('data', function (c) { replydata += c.toString(); }); + pws.stdin.write(cmd + '\r\nexit\r\n'); + pws.on('exit', function () { + if (replydata != "") reply.installedBy = replydata; + mesh.SendCommand({ action: 'msg', type: 'service', value: JSON.stringify(reply), sessionid: data.sessionid }); + delete pws; + }); + } else { + mesh.SendCommand({ action: 'msg', type: 'service', value: JSON.stringify(reply), sessionid: data.sessionid }); + } + } + } catch (ex) { + mesh.SendCommand({ action: 'msg', type: 'service', error: ex, sessionid: data.sessionid }) + } + } case 'services': { // Return the list of installed services var services = null; @@ -1338,11 +1397,13 @@ function handleServerCommand(data) { child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stderr.on('data', function () { }); child.waitExit(); + mesh.SendCommand({ action: 'msg', type: 'deskBackground', sessionid: data.sessionid, data: (current != '' ? "" : require('MeshAgent')._wallpaper), }); } else { var id = require('user-sessions').consoleUid(); var current = require('linux-gnome-helpers').getDesktopWallpaper(id); if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; } require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper); + mesh.SendCommand({ action: 'msg', type: 'deskBackground', sessionid: data.sessionid, data: (current != '/dev/null' ? "" : require('MeshAgent')._wallpaper), }); } } catch (ex) { sendConsoleText(ex); @@ -1446,6 +1507,14 @@ function handleServerCommand(data) { sendConsoleText('localappMsg: ' + data.appid + ', ' + JSON.stringify(data.value)); if (data.appid != null) { sendToRegisteredApp(data.appid, data.value); } else { broadcastToRegisteredApps(data.value); } break; + case 'alertbox': { + // Display an old style alert box + if (data.title && data.msg) { + MeshServerLogEx(158, [data.title, data.msg], "Displaying alert box, title=" + data.title + ", message=" + data.msg, data); + try { require('message-box').create(data.title, data.msg, 9999, 1).then(function () { }).catch(function () { }); } catch (ex) { } + } + break; + } default: // Unknown action, ignore it. break; @@ -1469,7 +1538,7 @@ function handleServerCommand(data) { } case 'runcommands': { if (mesh.cmdchild != null) { sendConsoleText("Run commands can't execute, already busy."); break; } - sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds); + if (!data.reply) sendConsoleText("Run commands (" + data.runAsUser + "): " + data.cmds); // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly var options = {}; @@ -1481,33 +1550,57 @@ function handleServerCommand(data) { if (options.uid == null) break; if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user. } - + var replydata = ""; if (process.platform == 'win32') { if (data.type == 1) { // Windows command shell mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options); mesh.cmdchild.descriptorMetadata = 'UserCommandsShell'; - mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); }); - mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); }); + mesh.cmdchild.stdout.on('data', function (c) { replydata += c.toString(); }); + mesh.cmdchild.stderr.on('data', function (c) { replydata += c.toString(); }); mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n'); - mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; }); + mesh.cmdchild.on('exit', function () { + if (data.reply) { + mesh.SendCommand({ action: 'msg', type: 'runcommands', result: replydata, sessionid: data.sessionid, responseid: data.responseid }); + } else { + sendConsoleText(replydata); + sendConsoleText("Run commands completed."); + } + delete mesh.cmdchild; + }); } else if (data.type == 2) { // Windows Powershell mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options); mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell'; - mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); }); - mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); }); + mesh.cmdchild.stdout.on('data', function (c) { replydata += c.toString(); }); + mesh.cmdchild.stderr.on('data', function (c) { replydata += c.toString(); }); mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n'); - mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; }); + mesh.cmdchild.on('exit', function () { + if (data.reply) { + mesh.SendCommand({ action: 'msg', type: 'runcommands', result: replydata, sessionid: data.sessionid, responseid: data.responseid }); + } else { + sendConsoleText(replydata); + sendConsoleText("Run commands completed."); + } + delete mesh.cmdchild; + }); } } else if (data.type == 3) { // Linux shell mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options); mesh.cmdchild.descriptorMetadata = 'UserCommandsShell'; - mesh.cmdchild.stdout.on('data', function (c) { sendConsoleText(c.toString()); }); - mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); }); + mesh.cmdchild.stdout.on('data', function (c) { replydata += c.toString(); }); + mesh.cmdchild.stderr.on('data', function (c) { replydata += c.toString(); }); mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n'); - mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; }); + mesh.cmdchild.on('exit', function () { + if (data.reply) { + mesh.SendCommand({ action: 'msg', type: 'runcommands', result: replydata, sessionid: data.sessionid, responseid: data.responseid }); + } else { + sendConsoleText(replydata); + sendConsoleText("Run commands completed."); + } + delete mesh.cmdchild; + }); } break; } @@ -1785,7 +1878,7 @@ function onFileWatcher(a, b) { */ // Replace all key name spaces with _ in an object recursively. -// This is a workaround since require('identifiers').get() returns key names with spaces in them on Linux. +// This is a workaround since require('computer-identifiers').get() returns key names with spaces in them on Linux. function replaceSpacesWithUnderscoresRec(o) { if (typeof o != 'object') return; for (var i in o) { if (i.indexOf(' ') >= 0) { o[i.split(' ').join('_')] = o[i]; delete o[i]; } replaceSpacesWithUnderscoresRec(o[i]); } @@ -1793,8 +1886,7 @@ function replaceSpacesWithUnderscoresRec(o) { function getSystemInformation(func) { try { - var results = { hardware: require('identifiers').get() }; // Hardware info - + var results = { hardware: require('computer-identifiers').get() }; // Hardware info if (results.hardware && results.hardware.windows) { // Remove extra entries and things that change quickly var x = results.hardware.windows.osinfo; @@ -1810,35 +1902,68 @@ function getSystemInformation(func) { if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; } if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } } } catch (ex) { } + if (x.LastBootUpTime) { // detect windows uptime + var thedate = { + year: parseInt(x.LastBootUpTime.substring(0, 4)), + month: parseInt(x.LastBootUpTime.substring(4, 6)) - 1, // Months are 0-based in JavaScript (0 - January, 11 - December) + day: parseInt(x.LastBootUpTime.substring(6, 8)), + hours: parseInt(x.LastBootUpTime.substring(8, 10)), + minutes: parseInt(x.LastBootUpTime.substring(10, 12)), + seconds: parseInt(x.LastBootUpTime.substring(12, 14)), + }; + var thelastbootuptime = new Date(thedate.year, thedate.month, thedate.day, thedate.hours, thedate.minutes, thedate.seconds); + meshCoreObj.lastbootuptime = thelastbootuptime.getTime(); // store the last boot up time in coreinfo for columns + meshCoreObjChanged(); + var nowtime = new Date(); + var differenceInMilliseconds = Math.abs(thelastbootuptime - nowtime); + if (differenceInMilliseconds < 300000) { // computer uptime less than 5 minutes + MeshServerLogEx(159, [thelastbootuptime.toString()], "Device Powered On", null); + } + } } + if(results.hardware && results.hardware.linux) { + if(results.hardware.linux.LastBootUpTime) { + var thelastbootuptime = new Date(results.hardware.linux.LastBootUpTime); + meshCoreObj.lastbootuptime = thelastbootuptime.getTime(); // store the last boot up time in coreinfo for columns + meshCoreObjChanged(); + var nowtime = new Date(); + var differenceInMilliseconds = Math.abs(thelastbootuptime - nowtime); + if (differenceInMilliseconds < 300000) { // computer uptime less than 5 minutes + MeshServerLogEx(159, [thelastbootuptime.toString()], "Device Powered On", null); + } + } + } + if(results.hardware && results.hardware.darwin){ + if(results.hardware.darwin.LastBootUpTime) { + var thelastbootuptime = new Date(results.hardware.darwin.LastBootUpTime * 1000); // must times by 1000 even tho timestamp is correct? + meshCoreObj.lastbootuptime = thelastbootuptime.getTime(); // store the last boot up time in coreinfo for columns + meshCoreObjChanged(); + var nowtime = new Date(); + var differenceInMilliseconds = Math.abs(thelastbootuptime - nowtime); + if (differenceInMilliseconds < 300000) { // computer uptime less than 5 minutes + MeshServerLogEx(159, [thelastbootuptime.toString()], "Device Powered On", null); + } + } + } results.hardware.agentvers = process.versions; + results.hardware.network = { dns: require('os').dns() }; replaceSpacesWithUnderscoresRec(results); var hasher = require('SHA384Stream').create(); - results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); - func(results); - /* // On Windows platforms, get volume information - Needs more testing. if (process.platform == 'win32') { results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot - - if (require('identifiers').volumes_promise != null) + if (require('win-volumes').volumes_promise != null) { - var p = require('identifiers').volumes_promise(); + var p = require('win-volumes').volumes_promise(); p.then(function (res) { - results.volumes = res; + results.hardware.windows.volumes = cleanGetBitLockerVolumeInfo(res); results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); }); } - else if (require('identifiers').volumes != null) - { - results.volumes = require('identifiers').volumes(); - results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); - func(results); - } else { results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); @@ -1850,7 +1975,7 @@ function getSystemInformation(func) { results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); } - */ + } catch (ex) { func(null, ex); } } @@ -1860,11 +1985,10 @@ function getDirectoryInfo(reqpath) { if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) { // List all the drives in the root, or the root itself var results = null; - try { results = fs.readDrivesSync(); } catch (ex) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar. + try { results = fs.readDrivesSync(); } catch (ex) { } if (results != null) { for (var i = 0; i < results.length; ++i) { - var drive = { n: results[i].name, t: 1 }; - if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons. + var drive = { n: results[i].name, t: 1, dt: results[i].type, s: (results[i].size ? results[i].size : 0), f: (results[i].free ? results[i].free : 0) }; response.dir.push(drive); } } @@ -2191,6 +2315,59 @@ function terminal_end() } +function terminal_consent_ask(ws) { + ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); + var consentMessage = currentTranslation['terminalConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); + var consentTitle = 'MeshCentral'; + if (ws.httprequest.soptions != null) { + if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; } + if (ws.httprequest.soptions.consentMsgTerminal != null) { consentMessage = ws.httprequest.soptions.consentMsgTerminal.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); } + } + if (process.platform == 'win32') { + var enhanced = false; + if (ws.httprequest.oldStyle === false) { + try { require('win-userconsent'); enhanced = true; } catch (ex) { } + } + if (enhanced) { + var ipr = server_getUserImage(ws.httprequest.userid); + ipr.consentTitle = consentTitle; + ipr.consentMessage = consentMessage; + ipr.consentTimeout = ws.httprequest.consentTimeout; + ipr.consentAutoAccept = ws.httprequest.consentAutoAccept; + ipr.username = ws.httprequest.realname; + ipr.tsid = ws.tsid; + ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage }; + ws.httprequest.tpromise._consent = ipr.then(function (img) { + this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground }); + this.__childPromise.close = this.consent.close.bind(this.consent); + return (this.consent); + }); + } else { + ws.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout); + } + } else { + ws.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout); + } + ws.httprequest.tpromise._consent.retPromise = ws.httprequest.tpromise; + ws.httprequest.tpromise._consent.then(function (always) { + if (always && process.platform == 'win32') { server_set_consentTimer(this.retPromise.httprequest.userid); } + // Success + MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest); + this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 })); + this.retPromise._consent = null; + this.retPromise._res(); + }, function (e) { + if (this.retPromise.that) { + if(this.retPromise.that.httprequest){ // User Consent Denied + MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest); + } else { } // Connection was closed server side, maybe log some messages somewhere? + this.retPromise._consent = null; + this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); + } else { } // no websocket, maybe log some messages somewhere? + this.retPromise._rej(e.toString()); + }); +} + function terminal_promise_connection_rejected(e) { // FAILED to connect terminal @@ -2243,7 +2420,7 @@ function terminal_promise_connection_resolved(term) if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) { // User Notifications is required - var notifyMessage = currentTranslation['terminalNotify'].replace('{0}', this.ws.httprequest.username); + var notifyMessage = currentTranslation['terminalNotify'].replace('{0}', this.ws.httprequest.realname ? this.ws.httprequest.realname : this.ws.httprequest.username); var notifyTitle = "MeshCentral"; if (this.ws.httprequest.soptions != null) { @@ -2472,7 +2649,7 @@ function tunnel_kvm_end() this.httprequest.desktop.kvm.users.splice(i, 1); this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close'); this.httprequest.desktop.kvm.connectionBar.close(); - this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid, color_options); + this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options); this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest; this.httprequest.desktop.kvm.connectionBar.on('close', function () { @@ -2503,13 +2680,111 @@ function kvm_tunnel_consentpromise_closehandler() if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } } +function kvm_consent_ok(ws) { + // User Consent Prompt is not required because no user is present + if (ws.httprequest.consent && (ws.httprequest.consent & 1)){ + // User Notifications is required + MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest); + var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', ws.httprequest.realname); + var notifyTitle = "MeshCentral"; + if (ws.httprequest.soptions != null) { + if (ws.httprequest.soptions.notifyTitle != null) { notifyTitle = ws.httprequest.soptions.notifyTitle; } + if (ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); } + } + try { require('toaster').Toast(notifyTitle, notifyMessage, ws.tsid); } catch (ex) { } + } else { + MeshServerLogEx(36, null, "Started remote desktop without notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest); + } + if (ws.httprequest.consent && (ws.httprequest.consent & 0x40)) { + // Connection Bar is required + if (ws.httprequest.desktop.kvm.connectionBar) { + ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close'); + ws.httprequest.desktop.kvm.connectionBar.close(); + } + try { + ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(ws.httprequest.privacybartext.replace('{0}', ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', ws.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options); + MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + ws.httprequest.remoteaddr + ")", ws.httprequest); + } catch (ex) { + MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + ws.httprequest.remoteaddr + ")", ws.httprequest); + } + if (ws.httprequest.desktop.kvm.connectionBar) { + ws.httprequest.desktop.kvm.connectionBar.state = { + userid: ws.httprequest.userid, + xuserid: ws.httprequest.xuserid, + username: ws.httprequest.username, + sessionid: ws.httprequest.sessionid, + remoteaddr: ws.httprequest.remoteaddr, + guestname: ws.httprequest.guestname, + desktop: ws.httprequest.desktop + }; + ws.httprequest.desktop.kvm.connectionBar.on('close', function () { + console.info1('Connection Bar Forcefully closed'); + MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", this.state); + for (var i in this.state.desktop.kvm._pipedStreams) { + this.state.desktop.kvm._pipedStreams[i].end(); + } + this.state.desktop.kvm.end(); + }); + } + } + ws.httprequest.desktop.kvm.pipe(ws, { dataTypeSkip: 1 }); + if (ws.httprequest.autolock) { + destopLockHelper_pipe(ws.httprequest); + } +} + +function kvm_consent_ask(ws){ + // Send a console message back using the console channel, "\n" is supported. + ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); + var consentMessage = currentTranslation['desktopConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); + var consentTitle = 'MeshCentral'; + if (ws.httprequest.soptions != null) { + if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; } + if (ws.httprequest.soptions.consentMsgDesktop != null) { consentMessage = ws.httprequest.soptions.consentMsgDesktop.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); } + } + var pr; + if (process.platform == 'win32') { + var enhanced = false; + if (ws.httprequest.oldStyle === false) { + try { require('win-userconsent'); enhanced = true; } catch (ex) { } + } + if (enhanced) { + var ipr = server_getUserImage(ws.httprequest.userid); + ipr.consentTitle = consentTitle; + ipr.consentMessage = consentMessage; + ipr.consentTimeout = ws.httprequest.consentTimeout; + ipr.consentAutoAccept = ws.httprequest.consentAutoAccept; + ipr.tsid = ws.tsid; + ipr.username = ws.httprequest.realname; + ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage }; + pr = ipr.then(function (img) { + this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translation, background: color_options.background, foreground: color_options.foreground }); + this.__childPromise.close = this.consent.close.bind(this.consent); + return (this.consent); + }); + } else { + pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null, ws.tsid); + } + } else { + pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null, ws.tsid); + } + pr.ws = ws; + ws.pause(); + ws._consentpromise = pr; + ws.prependOnceListener('end', kvm_tunnel_consentpromise_closehandler); + pr.then(kvm_consentpromise_resolved, kvm_consentpromise_rejected); +} + function kvm_consentpromise_rejected(e) { - // User Consent Denied/Failed - this.ws._consentpromise = null; - MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); - this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); - this.ws = null; + if (this.ws) { + if(this.ws.httprequest){ // User Consent Denied + MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); + } else { } // Connection was closed server side, maybe log some messages somewhere? + this.ws._consentpromise = null; + this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); + this.ws = null; + } else { } // no websocket, maybe log some messages somewhere? } function kvm_consentpromise_resolved(always) { @@ -2541,7 +2816,7 @@ function kvm_consentpromise_resolved(always) } try { - this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid, color_options); + this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options); MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); } catch (ex) { @@ -2550,27 +2825,24 @@ function kvm_consentpromise_resolved(always) MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); } } - if (this.ws.httprequest.desktop.kvm.connectionBar) + try { + if (this.ws.httprequest.desktop.kvm.connectionBar) { + this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest; + this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () { + MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest); + for (var i in this.httprequest.desktop.kvm._pipedStreams) { + this.httprequest.desktop.kvm._pipedStreams[i].end(); + } + this.httprequest.desktop.kvm.end(); + }); + } + } + catch (ex) { - this.ws.httprequest.desktop.kvm.connectionBar.state = + if (process.platform != 'darwin') { - userid: this.ws.httprequest.userid, - xuserid: this.ws.httprequest.xuserid, - username: this.ws.httprequest.username, - sessionid: this.ws.httprequest.sessionid, - remoteaddr: this.ws.httprequest.remoteaddr, - guestname: this.ws.httprequest.guestname, - desktop: this.ws.httprequest.desktop - }; - this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () - { - MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", state); - for (var i in this.state.desktop.kvm._pipedStreams) - { - this.state.desktop.kvm._pipedStreams[i].end(); - } - this.state.desktop.kvm.end(); - }); + MeshServerLogEx(32, null, "Failed2(" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); + } } } this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 }); @@ -2582,6 +2854,67 @@ function kvm_consentpromise_resolved(always) this.ws = null; } +function files_consent_ok(ws){ + // User Consent Prompt is not required + if (ws.httprequest.consent && (ws.httprequest.consent & 4)) { + // User Notifications is required + MeshServerLogEx(42, null, "Started remote files with toast notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest); + var notifyMessage = currentTranslation['fileNotify'].replace('{0}', ws.httprequest.realname); + var notifyTitle = "MeshCentral"; + if (ws.httprequest.soptions != null) { + if (ws.httprequest.soptions.notifyTitle != null) { notifyTitle = ws.httprequest.soptions.notifyTitle; } + if (ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = ws.httprequest.soptions.notifyMsgFiles.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); } + } + try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { } + } else { + MeshServerLogEx(43, null, "Started remote files without notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest); + } + ws.resume(); +} + +function files_consent_ask(ws){ + // Send a console message back using the console channel, "\n" is supported. + ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); + var consentMessage = currentTranslation['fileConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); + var consentTitle = 'MeshCentral'; + + if (ws.httprequest.soptions != null) { + if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; } + if (ws.httprequest.soptions.consentMsgFiles != null) { consentMessage = ws.httprequest.soptions.consentMsgFiles.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); } + } + var pr; + if (process.platform == 'win32') { + var enhanced = false; + if (ws.httprequest.oldStyle === false) { + try { require('win-userconsent'); enhanced = true; } catch (ex) { } + } + if (enhanced) { + var ipr = server_getUserImage(ws.httprequest.userid); + ipr.consentTitle = consentTitle; + ipr.consentMessage = consentMessage; + ipr.consentTimeout = ws.httprequest.consentTimeout; + ipr.consentAutoAccept = ws.httprequest.consentAutoAccept; + ipr.username = ws.httprequest.realname; + ipr.tsid = ws.tsid; + ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage }; + pr = ipr.then(function (img) { + this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground }); + this.__childPromise.close = this.consent.close.bind(this.consent); + return (this.consent); + }); + } else { + pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null); + } + } else { + pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null); + } + pr.ws = ws; + ws.pause(); + ws._consentpromise = pr; + ws.prependOnceListener('end', files_tunnel_endhandler); + pr.then(files_consentpromise_resolved, files_consentpromise_rejected); +} + function files_consentpromise_resolved(always) { if (always && process.platform == 'win32') { server_set_consentTimer(this.ws.httprequest.userid); } @@ -2607,11 +2940,14 @@ function files_consentpromise_resolved(always) } function files_consentpromise_rejected(e) { - // User Consent Denied/Failed - this.ws._consentpromise = null; - MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); - this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); - this.ws = null; + if (this.ws) { + if(this.ws.httprequest){ // User Consent Denied + MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); + } else { } // Connection was closed server side, maybe log some messages somewhere? + this.ws._consentpromise = null; + this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); + this.ws = null; + } else { } // no websocket, maybe log some messages somewhere? } function files_tunnel_endhandler() { @@ -2692,6 +3028,12 @@ function onTunnelData(data) this.descriptorMetadata = "Remote Terminal"; + // Look for a TSID + var tsid = null; + if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; } + require('MeshAgent')._tsid = tsid; + this.tsid = tsid; + if (process.platform == 'win32') { if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) { @@ -2708,71 +3050,31 @@ function onTunnelData(data) this.end = terminal_end; // Perform User-Consent if needed. - if (this.httprequest.consent && (this.httprequest.consent & 16)) - { - this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); - var consentMessage = currentTranslation['terminalConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); - var consentTitle = 'MeshCentral'; - - if (this.httprequest.soptions != null) - { - if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; } - if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); } - } - if (process.platform == 'win32') - { - var enhanced = false; - try { require('win-userconsent'); enhanced = true; } catch (ex) { } - if (enhanced) - { - var ipr = server_getUserImage(this.httprequest.userid); - ipr.consentTitle = consentTitle; - ipr.consentMessage = consentMessage; - ipr.consentTimeout = this.httprequest.consentTimeout; - ipr.consentAutoAccept = this.httprequest.consentAutoAccept; - ipr.username = this.httprequest.realname; - ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage }; - this.httprequest.tpromise._consent = ipr.then(function (img) - { - this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground }); - this.__childPromise.close = this.consent.close.bind(this.consent); - return (this.consent); - }); - } else - { - this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout); - } - } else - { - this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout); - } - this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise; - this.httprequest.tpromise._consent.then( - function (always) - { - if (always && process.platform == 'win32') { server_set_consentTimer(this.retPromise.httprequest.userid); } - - // Success - MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest); - this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 })); - this.retPromise._consent = null; - this.retPromise._res(); - }, - function (e) { - // Denied - MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest); - this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); - this.retPromise._consent = null; - this.retPromise._rej(e.toString()); + if (this.httprequest.consent && (this.httprequest.consent & 16)) { + // User asked for consent so now we check if we can auto accept if no user is present/loggedin + if (this.httprequest.consentAutoAcceptIfNoUser) { + var p = require('user-sessions').enumerateUsers(); + p.sessionid = this.httprequest.sessionid; + p.ws = this; + p.then(function (u) { + var v = []; + for (var i in u) { + if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); } + } + if (v.length == 0) { // No user is present, auto accept + this.ws.httprequest.tpromise._res(); + } else { + // User is present so we still need consent + terminal_consent_ask(this.ws); + } }); - } - else - { + } else { + terminal_consent_ask(this); + } + } else { // User-Consent is not required, so just resolve this promise this.httprequest.tpromise._res(); } - - this.httprequest.tpromise.then(terminal_promise_consent_resolved, terminal_promise_consent_rejected); } else if (this.httprequest.protocol == 2) @@ -2796,7 +3098,22 @@ function onTunnelData(data) var tsid = null; if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; } require('MeshAgent')._tsid = tsid; + this.tsid = tsid; + // If MacOS, Wake up device with caffeinate + if(process.platform == 'darwin'){ + try { + var options = {}; + try { options.uid = require('user-sessions').consoleUid(); } catch (ex) { } + options.type = require('child_process').SpawnTypes.TERM; + var replydata = ""; + var cmdchild = require('child_process').execFile('/usr/bin/caffeinate', ['caffeinate', '-u', '-t', '10'], options); + cmdchild.descriptorMetadata = 'UserCommandsShell'; + cmdchild.stdout.on('data', function (c) { replydata += c.toString(); }); + cmdchild.stderr.on('data', function (c) { replydata + c.toString(); }); + cmdchild.on('exit', function () { delete cmdchild; }); + } catch(err) { } + } // Remote desktop using native pipes this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(tsid), tunnel: this }; this.httprequest.desktop.kvm.parent = this.httprequest.desktop; @@ -2853,117 +3170,33 @@ function onTunnelData(data) } // Perform notification if needed. Toast messages may not be supported on all platforms. - if (this.httprequest.consent && (this.httprequest.consent & 8)) - { - // User Consent Prompt is required - // Send a console message back using the console channel, "\n" is supported. - this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); - var consentMessage = currentTranslation['desktopConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); - var consentTitle = 'MeshCentral'; - if (this.httprequest.soptions != null) - { - if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; } - if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); } + if (this.httprequest.consent && (this.httprequest.consent & 8)) { + + // User asked for consent but now we check if can auto accept if no user is present + if (this.httprequest.consentAutoAcceptIfNoUser) { + // Get list of users to check if we any actual users logged in, and if users logged in, we still need consent + var p = require('user-sessions').enumerateUsers(); + p.sessionid = this.httprequest.sessionid; + p.ws = this; + p.then(function (u) { + var v = []; + for (var i in u) { + if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); } + } + if (v.length == 0) { // No user is present, auto accept + kvm_consent_ok(this.ws); + } else { + // User is present so we still need consent + kvm_consent_ask(this.ws); + } + }); + } else { + // User Consent Prompt is required + kvm_consent_ask(this); } - var pr; - if (process.platform == 'win32') - { - var enhanced = false; - try { require('win-userconsent'); enhanced = true; } catch (ex) { } - if (enhanced) - { - var ipr = server_getUserImage(this.httprequest.userid); - ipr.consentTitle = consentTitle; - ipr.consentMessage = consentMessage; - ipr.consentTimeout = this.httprequest.consentTimeout; - ipr.consentAutoAccept = this.httprequest.consentAutoAccept; - ipr.tsid = tsid; - ipr.username = this.httprequest.realname; - ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage }; - pr = ipr.then(function (img) - { - this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translation, background: color_options.background, foreground: color_options.foreground }); - this.__childPromise.close = this.consent.close.bind(this.consent); - return (this.consent); - }); - } - else - { - pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null, tsid); - } - } - else - { - pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null, tsid); - } - pr.ws = this; - this.pause(); - this._consentpromise = pr; - this.prependOnceListener('end', kvm_tunnel_consentpromise_closehandler); - pr.then(kvm_consentpromise_resolved, kvm_consentpromise_rejected); - } - else - { + } else { // User Consent Prompt is not required - if (this.httprequest.consent && (this.httprequest.consent & 1)) - { - // User Notifications is required - MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest); - var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', this.httprequest.realname); - var notifyTitle = "MeshCentral"; - if (this.httprequest.soptions != null) { - if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; } - if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); } - } - try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { } - } else - { - MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest); - } - if (this.httprequest.consent && (this.httprequest.consent & 0x40)) - { - // Connection Bar is required - if (this.httprequest.desktop.kvm.connectionBar) - { - this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close'); - this.httprequest.desktop.kvm.connectionBar.close(); - } - try - { - this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid, color_options); - MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest); - } catch (ex) { - MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest); - } - if (this.httprequest.desktop.kvm.connectionBar) - { - this.httprequest.desktop.kvm.connectionBar.state = - { - userid: this.httprequest.userid, - xuserid: this.httprequest.xuserid, - username: this.httprequest.username, - sessionid: this.httprequest.sessionid, - remoteaddr: this.httprequest.remoteaddr, - guestname: this.httprequest.guestname, - desktop: this.httprequest.desktop - }; - this.httprequest.desktop.kvm.connectionBar.on('close', function () - { - console.info1('Connection Bar Forcefully closed'); - MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", this.state); - for (var i in this.state.desktop.kvm._pipedStreams) - { - this.state.desktop.kvm._pipedStreams[i].end(); - } - this.state.desktop.kvm.end(); - }); - } - } - this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); - if (this.httprequest.autolock) - { - destopLockHelper_pipe(this.httprequest); - } + kvm_consent_ok(this); } this.removeAllListeners('data'); @@ -2985,6 +3218,12 @@ function onTunnelData(data) this.descriptorMetadata = "Remote Files"; + // Look for a TSID + var tsid = null; + if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; } + require('MeshAgent')._tsid = tsid; + this.tsid = tsid; + // Add the files session to the count to update the server if (this.httprequest.userid != null) { var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest); @@ -3007,69 +3246,31 @@ function onTunnelData(data) // Perform notification if needed. Toast messages may not be supported on all platforms. if (this.httprequest.consent && (this.httprequest.consent & 32)) { - // User Consent Prompt is required - // Send a console message back using the console channel, "\n" is supported. - this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); - var consentMessage = currentTranslation['fileConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); - var consentTitle = 'MeshCentral'; - - if (this.httprequest.soptions != null) - { - if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; } - if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); } - } - var pr; - if (process.platform == 'win32') - { - var enhanced = false; - try { require('win-userconsent'); enhanced = true; } catch (ex) { } - if (enhanced) - { - var ipr = server_getUserImage(this.httprequest.userid); - ipr.consentTitle = consentTitle; - ipr.consentMessage = consentMessage; - ipr.consentTimeout = this.httprequest.consentTimeout; - ipr.consentAutoAccept = this.httprequest.consentAutoAccept; - ipr.username = this.httprequest.realname; - ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage }; - pr = ipr.then(function (img) - { - this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground }); - this.__childPromise.close = this.consent.close.bind(this.consent); - return (this.consent); - }); - } else - { - pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null); - } - } - else - { - pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null); - } - pr.ws = this; - this.pause(); - this._consentpromise = pr; - this.prependOnceListener('end', files_tunnel_endhandler); - pr.then(files_consentpromise_resolved, files_consentpromise_rejected); - } - else - { - // User Consent Prompt is not required - if (this.httprequest.consent && (this.httprequest.consent & 4)) { - // User Notifications is required - MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest); - var notifyMessage = currentTranslation['fileNotify'].replace('{0}', this.httprequest.realname); - var notifyTitle = "MeshCentral"; - if (this.httprequest.soptions != null) { - if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; } - if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); } - } - try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { } + // User asked for consent so now we check if we can auto accept if no user is present/loggedin + if (this.httprequest.consentAutoAcceptIfNoUser) { + var p = require('user-sessions').enumerateUsers(); + p.sessionid = this.httprequest.sessionid; + p.ws = this; + p.then(function (u) { + var v = []; + for (var i in u) { + if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); } + } + if (v.length == 0) { // No user is present, auto accept + // User Consent Prompt is not required + files_consent_ok(this.ws); + } else { + // User is present so we still need consent + files_consent_ask(this.ws); + } + }); } else { - MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest); + // User Consent Prompt is required + files_consent_ask(this); } - this.resume(); + } else { + // User Consent Prompt is not required + files_consent_ok(this); } // Setup files @@ -3149,6 +3350,13 @@ function onTunnelData(data) } break; } + case 'open': { + // Open the local file/folder on the users desktop + if (cmd.path) { + MeshServerLogEx(20, [cmd.path], "Opening: " + cmd.path, cmd); + openFileOnDesktop(cmd.path); + } + } case 'markcoredump': { // If we are asking for the coredump file, set the right path. var coreDumpPath = null; @@ -3208,7 +3416,7 @@ function onTunnelData(data) if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; } } // Send the next download block(s) - while (sendNextBlock > 0) { + if (sendNextBlock > 0) { sendNextBlock--; var buf = Buffer.alloc(16384); var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null); @@ -3317,6 +3525,24 @@ function onTunnelData(data) this.zip.on('progress', require('events').moderated(function (name, p) { this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'zippingFile', file: ((process.platform == 'win32') ? (name.split('/').join('\\')) : name), progress: p }))); }, 1000)); this.zip.pipe(out); break; + case 'unzip': + if (this.unzip != null) return; // Unzip operating is currently running, exit now. + this.unzip = require('zip-reader').read(cmd.input); + this.unzip._dest = cmd.dest; + this.unzip.xws = this; + this.unzip.then(function (zipped) { + this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'unzipping' }))); + zipped.xws = this.xws; + zipped.extractAll(this._dest).then(function () { // finished extracting + zipped.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null }))); + zipped.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' }))); + delete zipped.xws.unzip; + }, function (e) { // error extracting + zipped.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'unziperror', error: e }))); + delete zipped.xws.unzip; + }); + }, function (e) { this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: 'unziperror', error: e }))); delete this.xws.unzip }); + break; case 'cancel': // Cancel zip operation if present try { this.zipcancel = true; this.zip.cancel(function () { }); } catch (ex) { } @@ -3532,7 +3758,14 @@ function onTunnelControlData(data, ws) { { // Desktop // Switch the user input from websocket to webrtc at this point. ws.unpipe(ws.httprequest.desktop.kvm); - try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (ex) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text. + if ((ws.httprequest.desktopviewonly != true) && ((ws.httprequest.rights == 0xFFFFFFFF) || (((ws.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((ws.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)))) { + // If we have remote control rights, pipe the KVM input + try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (ex) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text. + } else { + // We need to only pipe non-mouse & non-keyboard inputs. + // sendConsoleText('Warning: No Remote Desktop Input Rights.'); + // TODO!!! + } ws.resume(); // Resume the websocket to keep receiving control data } ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point. @@ -3591,6 +3824,64 @@ function consoleHttpResponse(response) { response.close = function () { sendConsoleText('httprequest.response.close', this.sessionid); consoleHttpRequest = null; } } +// Open a local file on current user's desktop +function openFileOnDesktop(file) { + var child = null; + try { + switch (process.platform) { + case 'win32': + var uid = require('user-sessions').consoleUid(); + var user = require('user-sessions').getUsername(uid); + var domain = require('user-sessions').getDomain(uid); + var task = { name: 'MeshChatTask', user: user, domain: domain, execPath: (require('fs').statSync(file).isDirectory() ? process.env['windir'] + '\\explorer.exe' : file) }; + if (require('fs').statSync(file).isDirectory()) task.arguments = [file]; + try { + require('win-tasks').addTask(task); + require('win-tasks').getTask({ name: 'MeshChatTask' }).run(); + require('win-tasks').deleteTask('MeshChatTask'); + return (true); + } + catch (ex) { + var taskoptions = { env: { _target: (require('fs').statSync(file).isDirectory() ? process.env['windir'] + '\\explorer.exe' : file), _user: '"' + domain + '\\' + user + '"' }, _args: "" }; + if (require('fs').statSync(file).isDirectory()) taskoptions.env._args = file; + for (var c1e in process.env) { + taskoptions.env[c1e] = process.env[c1e]; + } + var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], taskoptions); + child.stderr.on('data', function (c) { }); + child.stdout.on('data', function (c) { }); + child.stdin.write('SCHTASKS /CREATE /F /TN MeshChatTask /SC ONCE /ST 00:00 '); + if (user) { child.stdin.write('/RU $env:_user '); } + child.stdin.write('/TR "$env:_target $env:_args"\r\n'); + child.stdin.write('$ts = New-Object -ComObject Schedule.service\r\n'); + child.stdin.write('$ts.connect()\r\n'); + child.stdin.write('$tsfolder = $ts.getfolder("\\")\r\n'); + child.stdin.write('$task = $tsfolder.GetTask("MeshChatTask")\r\n'); + child.stdin.write('$taskdef = $task.Definition\r\n'); + child.stdin.write('$taskdef.Settings.StopIfGoingOnBatteries = $false\r\n'); + child.stdin.write('$taskdef.Settings.DisallowStartIfOnBatteries = $false\r\n'); + child.stdin.write('$taskdef.Actions.Item(1).Path = $env:_target\r\n'); + child.stdin.write('$taskdef.Actions.Item(1).Arguments = $env:_args\r\n'); + child.stdin.write('$tsfolder.RegisterTaskDefinition($task.Name, $taskdef, 4, $null, $null, $null)\r\n'); + child.stdin.write('SCHTASKS /RUN /TN MeshChatTask\r\n'); + child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\nexit\r\n'); + child.waitExit(); + } + break; + case 'linux': + child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', file], { uid: require('user-sessions').consoleUid() }); + break; + case 'darwin': + child = require('child_process').execFile('/usr/bin/open', ['open', file]); + break; + default: + // Unknown platform, ignore this command. + break; + } + } catch (ex) { } + return child; +} + // Open a web browser to a specified URL on current user's desktop function openUserDesktopUrl(url) { if ((url.toLowerCase().startsWith('http://') == false) && (url.toLowerCase().startsWith('https://') == false)) { return null; } @@ -3656,14 +3947,15 @@ function processConsoleCommand(cmd, args, rights, sessionid) { var response = null; switch (cmd) { case 'help': { // Displays available commands - var fin = '', f = '', availcommands = 'domain,translations,agentupdate,errorlog,msh,timerinfo,coreinfo,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,wslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,wallpaper,agentmsg,task'; + var fin = '', f = '', availcommands = 'domain,translations,agentupdate,errorlog,msh,timerinfo,coreinfo,coreinfoupdate,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,wslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,wallpaper,agentmsg,task,uninstallagent,display,openfile'; if (require('os').dns != null) { availcommands += ',dnsinfo'; } try { require('linux-dhcp'); availcommands += ',dhcp'; } catch (ex) { } if (process.platform == 'win32') { - availcommands += ',cs,wpfhwacceleration,uac,volumes'; + availcommands += ',bitlocker,cs,wpfhwacceleration,uac,volumes,rdpport,deskbackground'; if (bcdOK()) { availcommands += ',safemode'; } if (require('notifybar-desktop').DefaultPinned != null) { availcommands += ',privacybar'; } try { require('win-utils'); availcommands += ',taskbar'; } catch (ex) { } + try { require('win-info'); availcommands += ',installedapps,qfe'; } catch (ex) { } } if (amt != null) { availcommands += ',amt,amtconfig,amtevents'; } if (process.platform != 'freebsd') { availcommands += ',vm'; } @@ -3679,8 +3971,46 @@ function processConsoleCommand(cmd, args, rights, sessionid) { response = "Available commands: \r\n" + fin + "."; break; } + case 'mousetrails': + try { require('win-deskutils'); } catch (ex) { response = 'Unknown command "mousetrails", type "help" for list of available commands.'; break; } + var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : null; + switch (args['_'].length) + { + case 0: + var trails = require('win-deskutils').mouse.getTrails(id); + response = trails == 0 ? 'MouseTrails Disabled' : ('MouseTrails enabled (' + trails + ')'); + response += '\nTo change setting, specify a positive integer, where 0 is disable: mousetrails [n]'; + break; + case 1: + var trails = parseInt(args['_'][0]); + require('win-deskutils').mouse.setTrails(trails, id); + trails = require('win-deskutils').mouse.getTrails(id); + response = trails == 0 ? 'MouseTrails Disabled' : ('MouseTrails enabled (' + trails + ')'); + break; + default: + response = 'Proper usage: mousetrails [n]'; + break; + } + break; + case 'deskbackground': + try { require('win-deskutils'); } catch (ex) { response = 'Unknown command "deskbackground", type "help" for list of available commands.'; break; } + var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : null; + switch (args['_'].length) + { + case 0: + response = 'Desktop Background: ' + require('win-deskutils').background.get(id); + break; + case 1: + require('win-deskutils').background.set(args['_'][0], id); + response = 'Desktop Background: ' + require('win-deskutils').background.get(id); + break; + default: + response = 'Proper usage: deskbackground [path]'; + break; + } + break; case 'taskbar': - try { require('win-utils'); } catch (ex) { response = 'Unknown command "taskbar", type "help" for list of avaialble commands.'; break; } + try { require('win-utils'); } catch (ex) { response = 'Unknown command "taskbar", type "help" for list of available commands.'; break; } switch (args['_'].length) { case 1: case 2: @@ -3703,7 +4033,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { break; case 'privacybar': if (process.platform != 'win32' || require('notifybar-desktop').DefaultPinned == null) { - response = 'Unknown command "privacybar", type "help" for list of avaialble commands.'; + response = 'Unknown command "privacybar", type "help" for list of available commands.'; } else { switch (args['_'].length) { @@ -3736,7 +4066,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { case 'domaininfo': { if (process.platform != 'win32') { - response = 'Unknown command "cs", type "help" for list of avaialble commands.'; + response = 'Unknown command "cs", type "help" for list of available commands.'; break; } if (global._domainQuery != null) { @@ -3782,9 +4112,17 @@ function processConsoleCommand(cmd, args, rights, sessionid) { case 'volumes': response = JSON.stringify(require('win-volumes').getVolumes(), null, 1); break; + case 'bitlocker': + if (process.platform == 'win32') { + if (require('win-volumes').volumes_promise != null) { + var p = require('win-volumes').volumes_promise(); + p.then(function (res) { sendConsoleText(JSON.stringify(cleanGetBitLockerVolumeInfo(res), null, 1), this.session); }); + } + } + break; case 'dhcp': // This command is only supported on Linux, this is because Linux does not give us the DNS suffix for each network adapter independently so we have to ask the DHCP server. { - try { require('linux-dhcp'); } catch (ex) { response = 'Unknown command "dhcp", type "help" for list of avaialble commands.'; break; } + try { require('linux-dhcp'); } catch (ex) { response = 'Unknown command "dhcp", type "help" for list of available commands.'; break; } if (args['_'].length == 0) { var j = require('os').networkInterfaces(); var ifcs = []; @@ -3811,7 +4149,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { } case 'cs': if (process.platform != 'win32') { - response = 'Unknown command "cs", type "help" for list of avaialble commands.'; + response = 'Unknown command "cs", type "help" for list of available commands.'; break; } switch (args['_'].length) { @@ -3887,11 +4225,71 @@ function processConsoleCommand(cmd, args, rights, sessionid) { } break; case 'msh': - response = JSON.stringify(_MSH(), null, 2); + if (args['_'].length == 0) { + response = JSON.stringify(_MSH(), null, 2); + } else if (args['_'].length > 3) { + response = 'Proper usage: msh [get|set|delete]\r\nmsh get MeshServer\r\nmsh set abc "xyz"\r\nmsh delete abc'; + } else { + var mshFileName = process.execPath.replace('.exe','') + '.msh'; + switch (args['_'][0].toLocaleLowerCase()) { + case 'get': + if (typeof args['_'][1] != 'string' || args['_'].length > 2) { + response = 'Proper usage: msh get MeshServer'; + } else if(_MSH()[args['_'][1]]) { + response = _MSH()[args['_'][1]]; + } else { + response = "Unknown Value: " + args['_'][1]; + } + break; + case 'set': + if (typeof args['_'][1] != 'string' || typeof args['_'][2] != 'string') { + response = 'Proper usage: msh set abc "xyz"'; + } else { + var jsonToSave = _MSH(); + jsonToSave[args['_'][1]] = args['_'][2]; + var updatedContent = ''; + for (var key in jsonToSave) { + if (jsonToSave.hasOwnProperty(key)) { + updatedContent += key + '=' + jsonToSave[key] + '\n'; + } + } + try { + require('fs').writeFileSync(mshFileName, updatedContent); + response = "msh set " + args['_'][1] + " successful" + } catch (ex) { + response = "msh set " + args['_'][1] + " unsuccessful"; + } + } + break; + case 'delete': + if (typeof args['_'][1] != 'string') { + response = 'Proper usage: msh delete abc'; + } else { + var jsonToSave = _MSH(); + delete jsonToSave[args['_'][1]]; + var updatedContent = ''; + for (var key in jsonToSave) { + if (jsonToSave.hasOwnProperty(key)) { + updatedContent += key + '=' + jsonToSave[key] + '\n'; + } + } + try { + require('fs').writeFileSync(mshFileName, updatedContent); + response = "msh delete " + args['_'][1] + " successful" + } catch (ex) { + response = "msh delete " + args['_'][1] + " unsuccessful"; + } + } + break; + default: + response = 'Proper usage: msh [get|set|delete]\r\nmsh get MeshServer\r\nmsh set abc "xyz"\r\nmsh delete abc'; + break; + } + } break; case 'dnsinfo': if (require('os').dns == null) { - response = "Unknown command \"" + cmd + "\", type \"help\" for list of avaialble commands."; + response = "Unknown command \"" + cmd + "\", type \"help\" for list of available commands."; } else { response = 'DNS Servers: '; @@ -3905,6 +4303,44 @@ function processConsoleCommand(cmd, args, rights, sessionid) { case 'timerinfo': response = require('ChainViewer').getTimerInfo(); break; + case 'rdpport': + if (process.platform != 'win32') { + response = 'Unknown command "rdpport", type "help" for list of available commands.'; + return; + } + if (args['_'].length == 0) { + response = 'Proper usage: rdpport [get|default|PORTNUMBER]'; + } else { + switch (args['_'][0].toLocaleLowerCase()) { + case 'get': + var rdpport = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp', 'PortNumber'); + response = "Current RDP Port Set To: " + rdpport + '\r\n'; + break; + case 'default': + try { + require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp', 'PortNumber', 3389); + response = 'RDP Port Set To 3389, Please Dont Forget To Restart Your Computer To Fully Apply'; + } catch (ex) { + response = 'Unable to Set RDP Port To: 3389'; + } + break; + default: + if (isNaN(parseFloat(args['_'][0]))){ + response = 'Proper usage: rdpport [get|default|PORTNUMBER]'; + } else if(parseFloat(args['_'][0]) < 0 || args['_'][0] > 65535) { + response = 'RDP Port Must Be More Than 0 And Less Than 65535'; + } else { + try { + require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'System\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp', 'PortNumber', parseFloat(args['_'][0])); + response = 'RDP Port Set To ' + args['_'][0] + ', Please Dont Forget To Restart Your Computer To Fully Apply'; + } catch (ex) { + response = 'Unable to Set RDP Port To: '+args['_'][0]; + } + } + break; + } + } + break; case 'find': if (args['_'].length <= 1) { response = "Proper usage:\r\n find root criteria [criteria2] [criteria n...]"; @@ -3924,12 +4360,13 @@ function processConsoleCommand(cmd, args, rights, sessionid) { break; } case 'coreinfoupdate': { - sendPeriodicServerUpdate(); + sendPeriodicServerUpdate(null, true); + response = "Core Info Update Requested" break; } case 'agentmsg': { if (args['_'].length == 0) { - response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [index]\r\n agentmsg list"; // Display usage + response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [id]\r\n agentmsg list"; // Display usage } else { if ((args['_'][0] == 'add') && (args['_'].length > 1)) { var msgID, iconIndex = 0; @@ -4037,12 +4474,12 @@ function processConsoleCommand(cmd, args, rights, sessionid) { break; case 'unzip': if (args['_'].length == 0) { - response = "Proper usage: unzip input, destination"; // Display usage + response = "Proper usage: unzip input,destination"; // Display usage } else { var p = args['_'].join(' ').split(','); - if (p.length != 2) { response = "Proper usage: unzip input, destination"; break; } // Display usage - var prom = require('zip-reader').read(p[0]); - prom._dest = p[1]; + if (p.length != 2) { response = "Proper usage: unzip input,destination"; break; } // Display usage + var prom = require('zip-reader').read(p[0].trim()); + prom._dest = p[1].trim(); prom.self = this; prom.sessionid = sessionid; prom.then(function (zipped) { @@ -4074,7 +4511,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) { break; case 'uac': if (process.platform != 'win32') { - response = 'Unknown command "uac", type "help" for list of avaialble commands.'; + response = 'Unknown command "uac", type "help" for list of available commands.'; break; } if (args['_'].length != 1) { @@ -4109,14 +4546,14 @@ function processConsoleCommand(cmd, args, rights, sessionid) { } break; case 'vm': - response = 'Virtual Machine = ' + require('identifiers').isVM(); + response = 'Virtual Machine = ' + require('computer-identifiers').isVM(); break; case 'startupoptions': response = JSON.stringify(require('MeshAgent').getStartupOptions()); break; case 'kvmmode': if (require('MeshAgent').maxKvmTileSize == null) { - response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands."; + response = "Unknown command \"kvmmode\", type \"help\" for list of available commands."; } else { if (require('MeshAgent').maxKvmTileSize == 0) { @@ -4147,10 +4584,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) { if (process.platform == 'win32') { // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value var writtenSize = 0; - try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (ex) { response = ex; } + var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent')); + try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize'); } catch (ex) { response = ex; } if (writtenSize != actualSize) { response = "Size updated from: " + writtenSize + " to: " + actualSize; - try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (ex) { response = ex; } + try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize', actualSize); } catch (ex) { response = ex; } } else { response = "Agent Size: " + actualSize + " kb"; } } else @@ -4412,6 +4850,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) { else { if (openUserDesktopUrl(args['_'][0]) == null) { response = 'Failed.'; } else { response = 'Success.'; } } break; } + case 'openfile': { + if (args['_'].length != 1) { response = 'Proper usage: openfile (filepath)'; } // Display usage + else { if (openFileOnDesktop(args['_'][0]) == null) { response = 'Failed.'; } else { response = 'Success.'; } } + break; + } case 'users': { if (meshCoreObj.users == null) { response = 'Active users are unknown.'; } else { response = 'Active Users: ' + meshCoreObj.users.join(', ') + '.'; } require('user-sessions').enumerateUsers().then(function (u) { for (var i in u) { sendConsoleText(u[i]); } }); @@ -4523,8 +4966,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) { } case 'sysinfo': { // Return system information getSystemInformation(function (results, err) { - if (results == null) { sendConsoleText(err, this.sessionid); } else { + if (results == null) { + sendConsoleText(err, this.sessionid); + } else { sendConsoleText(JSON.stringify(results, null, 1), this.sessionid); + mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); } }); break; @@ -4537,7 +4983,9 @@ function processConsoleCommand(cmd, args, rights, sessionid) { response += '\r\nServer Connection: ' + mesh.isControlChannelConnected + ', State: ' + meshServerConnectionState + '.'; var oldNodeId = db.Get('OldNodeId'); if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; } + response += '\r\nNode ID: ' + Buffer.from(require('_agentNodeId')(), 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); if (process.platform == 'linux' || process.platform == 'freebsd') { response += '\r\nX11 support: ' + require('monitor-info').kvm_x11_support + '.'; } + response += '\r\nApplication Location: ' + process.cwd(); //response += '\r\Debug Console: ' + debugConsole + '.'; break; } @@ -4764,6 +5212,21 @@ function processConsoleCommand(cmd, args, rights, sessionid) { } break; } + case 'display': { + if (args['_'].length != 1) { + response = 'Proper usage: display (sleep | awake)'; + } else { + var sleepawake = [args['_'][0]]; + if(sleepawake=='sleep'){ + require('power-monitor').sleepDisplay() + }else if(sleepawake=='awake'){ + require('power-monitor').wakeDisplay() + + } + response = 'Setting Display To ' + sleepawake; + } + break; + } case 'sendall': { // Send a message to all consoles on this mesh sendConsoleText(args['_'].join(' ')); break; @@ -4928,8 +5391,21 @@ function processConsoleCommand(cmd, args, rights, sessionid) { } break; } + case 'installedapps': { + if(process.platform == 'win32'){ + require('win-info').installedApps().then(function (apps){ sendConsoleText(JSON.stringify(apps,null,1)); }); + } + break; + } + case 'qfe': { + if(process.platform == 'win32'){ + var qfe = require('win-info').qfe(); + sendConsoleText(JSON.stringify(qfe,null,1)); + } + break; + } default: { // This is an unknown command, return an error message - response = "Unknown command \"" + cmd + "\", type \"help\" for list of avaialble commands."; + response = "Unknown command \"" + cmd + "\", type \"help\" for list of available commands."; break; } } @@ -5192,12 +5668,12 @@ function windows_execve(name, agentfilename, sessionid) { sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3); return; } - + var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true }); var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize); var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true }); - var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + process.cwd() + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' + - ' "' + process.execPath + '" & copy "' + process.cwd() + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + process.cwd() + agentfilename + '.update.exe"', { wide: true }); + var arg2 = require('_GenericMarshal').CreateVariable('/C net stop "' + name + '" & "' + process.cwd() + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' + + ' "' + process.execPath + '" & copy "' + process.cwd() + agentfilename + '.update.exe" "' + process.execPath + '" & net start "' + name + '" & erase "' + process.cwd() + agentfilename + '.update.exe"', { wide: true }); arg1.pointerBuffer().copy(args.toBuffer()); arg2.pointerBuffer().copy(args.toBuffer(), require('_GenericMarshal').PointerSize); @@ -5387,6 +5863,7 @@ function handleServerConnection(state) { // Update the server on with basic info, logged in users and more advanced stuff, like Intel ME and Network Settings meInfoStr = null; + LastPeriodicServerUpdate = null; sendPeriodicServerUpdate(null, true); if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); // 20 minutes @@ -5428,6 +5905,7 @@ function sendNetworkUpdate(force) { function sendPeriodicServerUpdate(flags, force) { if (meshServerConnectionState == 0) return; // Not connected to server, do nothing. if (!flags) { flags = 0xFFFFFFFF; } + if (!force) { force = false; } // If we have a connected MEI, get Intel ME information if ((flags & 1) && (amt != null) && (amt.state == 2)) { @@ -5460,6 +5938,15 @@ function sendPeriodicServerUpdate(flags, force) { }); } catch (ex) { } } + + // Get Defender for Windows Server + try { + var d = require('win-info').defender(); + d.then(function(res){ + meshCoreObj.defender = res; + meshCoreObjChanged(); + }); + } catch (ex) { } } // Send available data right now @@ -5473,6 +5960,26 @@ function sendPeriodicServerUpdate(flags, force) { } } +// Sort the names in an object +function sortObject(obj) { return Object.keys(obj).sort().reduce(function(a, v) { a[v] = obj[v]; return a; }, {}); } + +// Fix the incoming data and cut down how much data we use +function cleanGetBitLockerVolumeInfo(volumes) { + for (var i in volumes) { + const v = volumes[i]; + if (typeof v.size == 'string') { v.size = parseInt(v.size); } + if (typeof v.sizeremaining == 'string') { v.sizeremaining = parseInt(v.sizeremaining); } + if (v.identifier == '') { delete v.identifier; } + if (v.name == '') { delete v.name; } + if (v.removable != true) { delete v.removable; } + if (v.cdrom != true) { delete v.cdrom; } + if (v.protectionStatus == 'On') { v.protectionStatus = true; } else { delete v.protectionStatus; } + if (v.volumeStatus == 'FullyDecrypted') { delete v.volumeStatus; } + if (v.recoveryPassword == '') { delete v.recoveryPassword; } + } + return sortObject(volumes); +} + // Once we are done collecting all the data, send to server if needed var LastPeriodicServerUpdate = null; var PeriodicServerUpdateNagleTimer = null; diff --git a/agents/modules_meshcmd/sysinfo.js b/agents/modules_meshcmd/sysinfo.js index 02c355d9..611a7b1a 100644 --- a/agents/modules_meshcmd/sysinfo.js +++ b/agents/modules_meshcmd/sysinfo.js @@ -225,19 +225,14 @@ function macos_memUtilization() function windows_thermals() { var ret = []; - child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', '/namespace:\\\\root\\wmi', 'PATH', 'MSAcpi_ThermalZoneTemperature', 'get', 'CurrentTemperature']); - child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); - child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); - child.waitExit(); - - if(child.stdout.str.trim!='') - { - var lines = child.stdout.str.trim().split('\r\n'); - for (var i = 1; i < lines.length; ++i) - { - if (lines[i].trim() != '') { ret.push(((parseFloat(lines[i]) / 10) - 273.15).toFixed(2)); } + try { + ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']); + if (ret[0]) { + for (var i = 0; i < ret.length; ++i) { + ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2); + } } - } + } catch (ex) { } return (ret); } @@ -285,16 +280,10 @@ function macos_thermals() return (ret); } -switch(process.platform) -{ - case 'linux': - module.exports = { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals }; - break; - case 'win32': - module.exports = { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals }; - break; - case 'darwin': - module.exports = { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals }; - break; -} +const platformConfig = { + linux: { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals }, + win32: { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals }, + darwin: { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals } +}; +module.exports = platformConfig[process.platform]; diff --git a/agents/modules_meshcore/computer-identifiers.js b/agents/modules_meshcore/computer-identifiers.js new file mode 100644 index 00000000..ce5e3520 --- /dev/null +++ b/agents/modules_meshcore/computer-identifiers.js @@ -0,0 +1,902 @@ +/* +Copyright 2019-2021 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +function trimIdentifiers(val) +{ + for(var v in val) + { + if (!val[v] || val[v] == 'None' || val[v] == '') { delete val[v]; } + } +} +function trimResults(val) +{ + var i, x; + for (i = 0; i < val.length; ++i) + { + for (x in val[i]) + { + if (x.startsWith('_')) + { + delete val[i][x]; + } + else + { + if (val[i][x] == null || val[i][x] == 0) + { + delete val[i][x]; + } + } + } + } +} +function brief(headers, obj) +{ + var i, x; + for (x = 0; x < obj.length; ++x) + { + for (i in obj[x]) + { + if (!headers.includes(i)) + { + delete obj[x][i]; + } + } + } + return (obj); +} + +function dataHandler(c) +{ + this.str += c.toString(); +} + +function linux_identifiers() +{ + var identifiers = {}; + var ret = {}; + var values = {}; + + if (!require('fs').existsSync('/sys/class/dmi/id')) { + if (require('fs').existsSync('/sys/firmware/devicetree/base/model')) { + if (require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim().startsWith('Raspberry')) { + identifiers['board_vendor'] = 'Raspberry Pi'; + identifiers['board_name'] = require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim(); + identifiers['board_serial'] = require('fs').readFileSync('/sys/firmware/devicetree/base/serial-number').toString().trim(); + const memorySlots = []; + var child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stdin.write('vcgencmd get_mem arm && vcgencmd get_mem gpu\nexit\n'); + child.waitExit(); + try { + const lines = child.stdout.str.trim().split('\n'); + if (lines.length == 2) { + memorySlots.push({ Locator: "ARM Memory", Size: lines[0].split('=')[1].trim() }) + memorySlots.push({ Locator: "GPU Memory", Size: lines[1].split('=')[1].trim() }) + ret.memory = { Memory_Device: memorySlots }; + } + } catch (xx) { } + } else { + throw('Unknown board'); + } + } else { + throw ('this platform does not have DMI statistics'); + } + } else { + var entries = require('fs').readdirSync('/sys/class/dmi/id'); + for (var i in entries) { + if (require('fs').statSync('/sys/class/dmi/id/' + entries[i]).isFile()) { + try { + ret[entries[i]] = require('fs').readFileSync('/sys/class/dmi/id/' + entries[i]).toString().trim(); + } catch(z) { } + if (ret[entries[i]] == 'None') { delete ret[entries[i]]; } + } + } + entries = null; + + identifiers['bios_date'] = ret['bios_date']; + identifiers['bios_vendor'] = ret['bios_vendor']; + identifiers['bios_version'] = ret['bios_version']; + identifiers['bios_serial'] = ret['product_serial']; + identifiers['board_name'] = ret['board_name']; + identifiers['board_serial'] = ret['board_serial']; + identifiers['board_vendor'] = ret['board_vendor']; + identifiers['board_version'] = ret['board_version']; + identifiers['product_uuid'] = ret['product_uuid']; + identifiers['product_name'] = ret['product_name']; + } + + try { + identifiers['bios_mode'] = (require('fs').statSync('/sys/firmware/efi').isDirectory() ? 'UEFI': 'Legacy'); + } catch (ex) { identifiers['bios_mode'] = 'Legacy'; } + + var child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stdin.write('cat /proc/cpuinfo | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n"); + child.waitExit(); + identifiers['cpu_name'] = child.stdout.str.trim(); + if (identifiers['cpu_name'] == "") { // CPU BLANK, check lscpu instead + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stdin.write('lscpu | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n"); + child.waitExit(); + identifiers['cpu_name'] = child.stdout.str.trim(); + } + child = null; + + + // Fetch GPU info + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stdin.write("lspci | grep ' VGA ' | tr '\\n' '`' | awk '{ a=split($0,lines" + ',"`"); printf "["; for(i=1;i1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $1, $2, $3, $4, $5}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n'); + child.waitExit(); + try { ret.volumes = JSON.parse(child.stdout.str.trim()); } catch (xx) { } + child = null; + + values.identifiers = identifiers; + values.linux = ret; + trimIdentifiers(values.identifiers); + + var dmidecode = require('lib-finder').findBinary('dmidecode'); + if (dmidecode != null) + { + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stderr.str = ''; child.stderr.on('data', dataHandler); + child.stdin.write(dmidecode + " -t memory | tr '\\n' '`' | "); + child.stdin.write(" awk '{ "); + child.stdin.write(' printf("[");'); + child.stdin.write(' comma="";'); + child.stdin.write(' c=split($0, lines, "``");'); + child.stdin.write(' for(i=1;i<=c;++i)'); + child.stdin.write(' {'); + child.stdin.write(' d=split(lines[i], val, "`");'); + child.stdin.write(' split(val[1], tokens, ",");'); + child.stdin.write(' split(tokens[2], dmitype, " ");'); + child.stdin.write(' dmi = dmitype[3]+0; '); + child.stdin.write(' if(dmi == 5 || dmi == 6 || dmi == 16 || dmi == 17)'); + child.stdin.write(' {'); + child.stdin.write(' ccx="";'); + child.stdin.write(' printf("%s{\\"%s\\": {", comma, val[2]);'); + child.stdin.write(' for(j=3;j1)'); + child.stdin.write(' {'); + child.stdin.write(' sub(/^[ \\t]*/,"",tmp[2]);'); + child.stdin.write(' gsub(/ /,"",tmp[1]);'); + child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", ccx, tmp[1], tmp[2]);'); + child.stdin.write(' ccx=",";'); + child.stdin.write(' }'); + child.stdin.write(' }'); + child.stdin.write(' printf("}}");'); + child.stdin.write(' comma=",";'); + child.stdin.write(' }'); + child.stdin.write(' }'); + child.stdin.write(' printf("]");'); + child.stdin.write("}'\nexit\n"); + child.waitExit(); + + try + { + var j = JSON.parse(child.stdout.str); + var i, key, key2; + for (i = 0; i < j.length; ++i) + { + for (key in j[i]) + { + delete j[i][key]['ArrayHandle']; + delete j[i][key]['ErrorInformationHandle']; + for (key2 in j[i][key]) + { + if (j[i][key][key2] == 'Unknown' || j[i][key][key2] == 'Not Specified' || j[i][key][key2] == '') + { + delete j[i][key][key2]; + } + } + } + } + + if(j.length > 0){ + var mem = {}; + for (i = 0; i < j.length; ++i) + { + for (key in j[i]) + { + if (mem[key] == null) { mem[key] = []; } + mem[key].push(j[i][key]); + } + } + values.linux.memory = mem; + } + } + catch (e) + { } + child = null; + } + + var usbdevices = require('lib-finder').findBinary('usb-devices'); + if (usbdevices != null) + { + var child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stderr.str = ''; child.stderr.on('data', dataHandler); + child.stdin.write(usbdevices + " | tr '\\n' '`' | "); + child.stdin.write(" awk '"); + child.stdin.write('{'); + child.stdin.write(' comma="";'); + child.stdin.write(' printf("[");'); + child.stdin.write(' len=split($0, group, "``");'); + child.stdin.write(' for(i=1;i<=len;++i)'); + child.stdin.write(' {'); + child.stdin.write(' comma2="";'); + child.stdin.write(' xlen=split(group[i], line, "`");'); + child.stdin.write(' scount=0;'); + child.stdin.write(' for(x=1;x0)'); + child.stdin.write(' {'); + child.stdin.write(' printf("%s{", comma); comma=",";'); + child.stdin.write(' for(x=1;x> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }; + try { + values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftTpm', "SELECT * FROM Win32_Tpm", ['IsActivated_InitialValue','IsEnabled_InitialValue','IsOwned_InitialValue','ManufacturerId','ManufacturerVersion','SpecVersion']); + if(values[0]) { + ret.tpm = { + SpecVersion: values[0].SpecVersion.split(",")[0], + ManufacturerId: IntToStr(values[0].ManufacturerId).replace(/[^\x00-\x7F]/g, ""), + ManufacturerVersion: values[0].ManufacturerVersion, + IsActivated: values[0].IsActivated_InitialValue, + IsEnabled: values[0].IsEnabled_InitialValue, + IsOwned: values[0].IsOwned_InitialValue, + } + } + } catch (ex) { } + + return (ret); +} +function macos_identifiers() +{ + var ret = { identifiers: {}, darwin: {} }; + var child; + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep board-id | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); + child.waitExit(); + ret.identifiers.board_name = child.stdout.str.trim(); + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformSerialNumber | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); + child.waitExit(); + ret.identifiers.board_serial = child.stdout.str.trim(); + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep manufacturer | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); + child.waitExit(); + ret.identifiers.board_vendor = child.stdout.str.trim(); + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep version | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); + child.waitExit(); + ret.identifiers.board_version = child.stdout.str.trim(); + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformUUID | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n'); + child.waitExit(); + ret.identifiers.product_uuid = child.stdout.str.trim(); + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('sysctl -n machdep.cpu.brand_string\nexit\n'); + child.waitExit(); + ret.identifiers.cpu_name = child.stdout.str.trim(); + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('system_profiler SPMemoryDataType\nexit\n'); + child.waitExit(); + var lines = child.stdout.str.trim().split('\n'); + if(lines.length > 0) { + const memorySlots = []; + if(lines[2].trim().includes('Memory Slots:')) { // OLD MACS WITH SLOTS + var memorySlots1 = child.stdout.str.split(/\n{2,}/).slice(3); + memorySlots1.forEach(function(slot,index) { + var lines = slot.split('\n'); + if(lines.length == 1){ // start here + if(lines[0].trim()!=''){ + var slotObj = { DeviceLocator: lines[0].trim().replace(/:$/, '') }; // Initialize name as an empty string + var nextline = memorySlots1[index+1].split('\n'); + nextline.forEach(function(line) { + if (line.trim() !== '') { + var parts = line.split(':'); + var key = parts[0].trim(); + var value = parts[1].trim(); + value = (key == 'Part Number' || key == 'Manufacturer') ? hexToAscii(parts[1].trim()) : parts[1].trim(); + slotObj[key.replace(' ','')] = value; // Store attribute in the slot object + } + }); + memorySlots.push(slotObj); + } + } + }); + } else { // NEW MACS WITHOUT SLOTS + memorySlots.push({ DeviceLocator: "Onboard Memory", Size: lines[2].split(":")[1].trim(), PartNumber: lines[3].split(":")[1].trim(), Manufacturer: lines[4].split(":")[1].trim() }) + } + ret.darwin.memory = memorySlots; + } + + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('diskutil info -all\nexit\n'); + child.waitExit(); + var sections = child.stdout.str.split('**********\n'); + if(sections.length > 0){ + var devices = []; + for (var i = 0; i < sections.length; i++) { + var lines = sections[i].split('\n'); + var deviceInfo = {}; + var wholeYes = false; + var physicalYes = false; + var oldmac = false; + for (var j = 0; j < lines.length; j++) { + var keyValue = lines[j].split(':'); + var key = keyValue[0].trim(); + var value = keyValue[1] ? keyValue[1].trim() : ''; + if (key === 'Virtual') oldmac = true; + if (key === 'Whole' && value === 'Yes') wholeYes = true; + if (key === 'Virtual' && value === 'No') physicalYes = true; + if(value && key === 'Device / Media Name'){ + deviceInfo['Caption'] = value; + } + if(value && key === 'Disk Size'){ + deviceInfo['Size'] = value.split(' ')[0] + ' ' + value.split(' ')[1]; + } + } + if (wholeYes) { + if (oldmac) { + if (physicalYes) devices.push(deviceInfo); + } else { + devices.push(deviceInfo); + } + } + } + ret.identifiers.storage_devices = devices; + } + + // Fetch storage volumes using df + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stdin.write('df -aHY | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $3, $4, $5, $10, $2}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n'); + child.waitExit(); + try { + ret.darwin.volumes = JSON.parse(child.stdout.str.trim()); + for (var index = 0; index < ret.darwin.volumes.length; index++) { + if (ret.darwin.volumes[index].type == 'auto_home'){ + ret.darwin.volumes.splice(index,1); + } + } + if (ret.darwin.volumes.length == 0) { // not sonima OS so dont show type for now + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', dataHandler); + child.stdin.write('df -aH | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\"},", $2, $3, $4, $9}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n'); + child.waitExit(); + try { + ret.darwin.volumes = JSON.parse(child.stdout.str.trim()); + for (var index = 0; index < ret.darwin.volumes.length; index++) { + if (ret.darwin.volumes[index].size == 'auto_home'){ + ret.darwin.volumes.splice(index,1); + } + } + } catch (xx) { } + } + } catch (xx) { } + child = null; + + // MacOS Last Boot Up Time + try { + child = require('child_process').execFile('/usr/sbin/sysctl', ['', 'kern.boottime']); // must include blank value at begining for some reason? + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stderr.on('data', function () { }); + child.waitExit(); + const timestampMatch = /\{ sec = (\d+), usec = \d+ \}/.exec(child.stdout.str.trim()); + if (!ret.darwin) { + ret.darwin = { LastBootUpTime: parseInt(timestampMatch[1]) }; + } else { + ret.darwin.LastBootUpTime = parseInt(timestampMatch[1]); + } + child = null; + } catch (ex) { } + + trimIdentifiers(ret.identifiers); + + child = null; + return (ret); +} + +function hexToAscii(hexString) { + if(!hexString.startsWith('0x')) return hexString.trim(); + hexString = hexString.startsWith('0x') ? hexString.slice(2) : hexString; + var str = ''; + for (var i = 0; i < hexString.length; i += 2) { + var hexPair = hexString.substr(i, 2); + str += String.fromCharCode(parseInt(hexPair, 16)); + } + str = str.replace(/[\u007F-\uFFFF]/g, ''); // Remove characters from 0x0080 to 0xFFFF + return str.trim(); +} + +function win_chassisType() +{ + // needs to be replaced with win-wmi but due to bug in win-wmi it doesnt handle arrays correctly + var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {}); + if (child == null) { return ([]); } + child.descriptorMetadata = 'process-manager'; + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write('Get-WmiObject Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes\r\n'); + child.stdin.write('exit\r\n'); + child.waitExit(); + try { + return (parseInt(child.stdout.str)); + } catch (e) { + return (2); // unknown + } +} + +function win_systemType() +{ + try { + var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT PCSystemType FROM Win32_ComputerSystem', ['PCSystemType']); + if (tokens[0]) { + return (parseInt(tokens[0]['PCSystemType'])); + } else { + return (parseInt(1)); // default is desktop + } + } catch (ex) { + return (parseInt(1)); // default is desktop + } + +} + +function win_formFactor(chassistype) +{ + var ret = 'DESKTOP'; + switch (chassistype) + { + case 11: // Handheld + case 30: // Tablet + case 31: // Convertible + case 32: // Detachable + ret = 'TABLET'; + break; + case 9: // Laptop + case 10: // Notebook + case 14: // Sub Notebook + ret = 'LAPTOP'; + break; + default: + ret = win_systemType() == 2 ? 'MOBILE' : 'DESKTOP'; + break; + } + + return (ret); +} + +switch(process.platform) +{ + case 'linux': + module.exports = { _ObjectID: 'identifiers', get: linux_identifiers }; + break; + case 'win32': + module.exports = { _ObjectID: 'identifiers', get: windows_identifiers, chassisType: win_chassisType, formFactor: win_formFactor, systemType: win_systemType }; + break; + case 'darwin': + module.exports = { _ObjectID: 'identifiers', get: macos_identifiers }; + break; + default: + module.exports = { get: function () { throw ('Unsupported Platform'); } }; + break; +} +module.exports.isDocker = function isDocker() +{ + if (process.platform != 'linux') { return (false); } + + var child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write("cat /proc/self/cgroup | tr '\n' '`' | awk -F'`' '{ split($1, res, " + '"/"); if(res[2]=="docker"){print "1";} }\'\nexit\n'); + child.waitExit(); + return (child.stdout.str != ''); +}; +module.exports.isBatteryPowered = function isBatteryOperated() +{ + var ret = false; + switch(process.platform) + { + default: + break; + case 'linux': + var devices = require('fs').readdirSync('/sys/class/power_supply'); + for (var i in devices) + { + if (require('fs').readFileSync('/sys/class/power_supply/' + devices[i] + '/type').toString().trim() == 'Battery') + { + ret = true; + break; + } + } + break; + case 'win32': + var GM = require('_GenericMarshal'); + var stats = GM.CreateVariable(12); + var kernel32 = GM.CreateNativeProxy('Kernel32.dll'); + kernel32.CreateMethod('GetSystemPowerStatus'); + if (kernel32.GetSystemPowerStatus(stats).Val != 0) + { + if(stats.toBuffer()[1] != 128 && stats.toBuffer()[1] != 255) + { + ret = true; + } + else + { + // No Battery detected, so lets check if there is supposed to be one + var formFactor = win_formFactor(win_chassisType()); + return (formFactor == 'LAPTOP' || formFactor == 'TABLET' || formFactor == 'MOBILE'); + } + } + break; + case 'darwin': + var child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function(c){ this.str += c.toString(); }); + child.stderr.str = ''; child.stderr.on('data', function(c){ this.str += c.toString(); }); + child.stdin.write("pmset -g batt | tr '\\n' '`' | awk -F'`' '{ if(NF>2) { print \"true\"; }}'\nexit\n"); + child.waitExit(); + if(child.stdout.str.trim() != '') { ret = true; } + break; + } + return (ret); +}; +module.exports.isVM = function isVM() +{ + var ret = false; + var id = this.get(); + if (id.linux && id.linux.sys_vendor) + { + switch (id.linux.sys_vendor) + { + case 'VMware, Inc.': + case 'QEMU': + case 'Xen': + ret = true; + break; + default: + break; + } + } + if (id.identifiers.bios_vendor) + { + switch(id.identifiers.bios_vendor) + { + case 'VMware, Inc.': + case 'Xen': + case 'SeaBIOS': + case 'EFI Development Kit II / OVMF': + case 'Proxmox distribution of EDK II': + ret = true; + break; + default: + break; + } + } + if (id.identifiers.board_vendor && id.identifiers.board_vendor == 'VMware, Inc.') { ret = true; } + if (id.identifiers.board_name) + { + switch (id.identifiers.board_name) + { + case 'VirtualBox': + case 'Virtual Machine': + ret = true; + break; + default: + break; + } + } + + if (process.platform == 'win32' && !ret) + { + for(var i in id.identifiers.gpu_name) + { + if(id.identifiers.gpu_name[i].startsWith('VMware ')) + { + ret = true; + break; + } + } + } + + + if (!ret) { ret = this.isDocker(); } + return (ret); +}; + +// bios_date = BIOS->ReleaseDate +// bios_vendor = BIOS->Manufacturer +// bios_version = BIOS->SMBIOSBIOSVersion +// board_name = BASEBOARD->Product = ioreg/board-id +// board_serial = BASEBOARD->SerialNumber = ioreg/serial-number | ioreg/IOPlatformSerialNumber +// board_vendor = BASEBOARD->Manufacturer = ioreg/manufacturer +// board_version = BASEBOARD->Version diff --git a/agents/modules_meshcore/coretranslations.json b/agents/modules_meshcore/coretranslations.json index 8da6fcfb..567a08f8 100644 --- a/agents/modules_meshcore/coretranslations.json +++ b/agents/modules_meshcore/coretranslations.json @@ -135,12 +135,12 @@ "allow": "Permitir", "deny": "Negar", "autoAllowForFive": "Aceita automaticamente todas as conexões pelos próximos 5 minutos", - "terminalConsent": "{0} solicitando acesso ao terminal remoto. Garantir acesso?", - "desktopConsent": "{0} solicitando acesso à área de trabalho remota. Garantir acesso?", - "fileConsent": "{0} solicitando acesso remoto ao arquivo. Garantir acesso?", + "terminalConsent": "{0} está a pedir acesso ao terminal remoto. Conceder acesso?", + "desktopConsent": "{0} está a pedir acesso à área de trabalho remota. Conceder acesso?", + "fileConsent": "{0} está a pedir acesso remoto aos ficheiros. Conceder acesso?", "terminalNotify": "{0} iniciou uma sessão de terminal remoto.", "desktopNotify": "{0} iniciou uma sessão de área de trabalho remota.", - "fileNotify": "{0} iniciou uma sessão de arquivo remoto.", + "fileNotify": "{0} iniciou uma sessão de ficheiro remoto.", "privacyBar": "Compartilhando área de trabalho com: {0}" }, "ru": { @@ -250,5 +250,41 @@ "desktopNotify": "{0} je započeo sesiju udaljene radne površine.", "fileNotify": "{0} je započeo sesiju udaljenog fajla.", "privacyBar": "Dijeljenje radne površine sa: {0}" + }, + "hu": { + "allow": "Engedélyezés", + "deny": "Elutasítás", + "autoAllowForFive": "Csatlakozások automatikus elfogadása a következő 5 percben", + "terminalConsent": "{0} távoli parancssor,terminál hozzáférést kér. Engedélyezi a hozzáférést?", + "desktopConsent": "{0} távoli asztali hozzáférést kér. Engedélyezi a hozzáférést?", + "fileConsent": "{0} távoli fájlhozzáférést kér. Engedélyezi a hozzáférést?", + "terminalNotify": "{0} távoli parancssor munkamenetet indított.", + "desktopNotify": "{0} távoli asztali munkamenetet indított.", + "fileNotify": "{0} távoli fájlmunkamenetet indított.", + "privacyBar": "Asztal megosztás aktív: {0} felhasználóval" + }, + "ca": { + "allow": "Permetre", + "deny": "Negar", + "autoAllowForFive": "Accepta automàticament totes les connexions durant els propers 5 minuts", + "terminalConsent": "{0} sol·licitant accés al terminal remot. Accés garantit?", + "desktopConsent": "{0} sol·licitant accés a l'escriptori remot. Accés garantit?", + "fileConsent": "{0} sol·licitant accés remot al fitxer. Accés garantit?", + "terminalNotify": "{0} va iniciar una sessió de terminal remota.", + "desktopNotify": "{0} va iniciar una sessió d'escriptori remot.", + "fileNotify": "{0} va iniciar una sessió de fitxer remota.", + "privacyBar": "Compartint escriptori amb: {0}" + }, + "uk": { + "allow": "Дозволити", + "deny": "Відмовити", + "autoAllowForFive": "Автоматично приймати всі підключення впродовж наступних 5 хвилин", + "terminalConsent": "{0} запитує доступ до віддаленого терміналу. Надати доступ?", + "desktopConsent": "{0} запитує віддалений доступ до стільниці. Надати доступ?", + "fileConsent": "{0} запитує віддалений доступ до файлу. Надати доступ?", + "terminalNotify": "{0} почав сеанс віддаленого терміналу.", + "desktopNotify": "{0} розпочав сеанс віддаленої стільниці.", + "fileNotify": "{0} розпочав віддалений файловий сеанс.", + "privacyBar": "Поширити доступ до стільниці з: {0}" } } \ No newline at end of file diff --git a/agents/modules_meshcore/sysinfo.js b/agents/modules_meshcore/sysinfo.js index 02c355d9..cc13574d 100644 --- a/agents/modules_meshcore/sysinfo.js +++ b/agents/modules_meshcore/sysinfo.js @@ -159,7 +159,7 @@ function linux_memUtilization() case 'MemTotal:': ret.total = parseInt(tokens[tokens.length - 2]); break; - case 'MemFree:': + case 'MemAvailable:': ret.free = parseInt(tokens[tokens.length - 2]); break; } @@ -209,9 +209,13 @@ function macos_memUtilization() { var usage = lines[0].split(':')[1]; var bdown = usage.split(','); - - mem.MemTotal = parseInt(bdown[0].trim().split(' ')[0]); - mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]); + if (bdown.length > 2){ // new style - PhysMem: 5750M used (1130M wired, 634M compressor), 1918M unused. + mem.MemFree = parseInt(bdown[2].trim().split(' ')[0]); + } else { // old style - PhysMem: 6683M used (1606M wired), 9699M unused. + mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]); + } + mem.MemUsed = parseInt(bdown[0].trim().split(' ')[0]); + mem.MemTotal = (mem.MemFree + mem.MemUsed); mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2); mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2); return (mem); @@ -225,31 +229,48 @@ function macos_memUtilization() function windows_thermals() { var ret = []; - child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', '/namespace:\\\\root\\wmi', 'PATH', 'MSAcpi_ThermalZoneTemperature', 'get', 'CurrentTemperature']); - child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); - child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); - child.waitExit(); - - if(child.stdout.str.trim!='') - { - var lines = child.stdout.str.trim().split('\r\n'); - for (var i = 1; i < lines.length; ++i) - { - if (lines[i].trim() != '') { ret.push(((parseFloat(lines[i]) / 10) - 273.15).toFixed(2)); } + try { + ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']); + if (ret[0]) { + for (var i = 0; i < ret.length; ++i) { + ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2); + } } - } + } catch (ex) { } return (ret); } function linux_thermals() { + var ret = []; child = require('child_process').execFile('/bin/sh', ['sh']); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); - child.stdin.write("cat /sys/class/thermal/thermal_zone*/temp | awk '{ print $0 / 1000 }'\nexit\n"); + child.stdin.write("for folder in /sys/class/thermal/thermal_zone*/; do [ -e \"$folder/temp\" ] && echo \"$(cat \"$folder/temp\"),$(cat \"$folder/type\")\"; done\nexit\n"); child.waitExit(); - var ret = child.stdout.str.trim().split('\n'); - if (ret.length == 1 && ret[0] == '') { ret = []; } + if(child.stdout.str.trim()!='') + { + var lines = child.stdout.str.trim().split('\n'); + for (var i = 0; i < lines.length; ++i) + { + var line = lines[i].trim().split(','); + ret.push({CurrentTemperature: (parseFloat(line[0])/1000), InstanceName: line[1]}); + } + } + child = require('child_process').execFile('/bin/sh', ['sh']); + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); + child.stdin.write("for mon in /sys/class/hwmon/hwmon*; do for label in \"$mon\"/temp*_label; do if [ -f $label ]; then echo $(cat \"$label\")___$(cat \"${label%_*}_input\"); fi; done; done;\nexit\n"); + child.waitExit(); + if(child.stdout.str.trim()!='') + { + var lines = child.stdout.str.trim().split('\n'); + for (var i = 0; i < lines.length; ++i) + { + var line = lines[i].trim().split('___'); + ret.push({ CurrentTemperature: (parseFloat(line[1])/1000), InstanceName: line[0] }); + } + } return (ret); } @@ -261,7 +282,6 @@ function macos_thermals() child.stderr.on('data', function () { }); child.stdin.write('powermetrics --help | grep SMC\nexit\n'); child.waitExit(); - if (child.stdout.str.trim() != '') { child = require('child_process').execFile('/bin/sh', ['sh']); @@ -273,14 +293,19 @@ function macos_thermals() { if (tokens[i].split(' die temperature: ').length > 1) { - ret.push(tokens[i].split(' ')[3]); + ret.push({CurrentTemperature: tokens[i].split(' ')[3], InstanceName: tokens[i].split(' ')[0]}); this.parent.kill(); } } }); - child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); - child.stdin.write('powermetrics -s smc\n'); - child.waitExit(5000); + child.stderr.on('data', function (c) { + if (c.toString().split('unable to get smc values').length > 1) { // error getting sensors so just kill + this.parent.kill(); + return; + } + }); + child.stdin.write('powermetrics -s smc -i 500 -n 1\n'); + child.waitExit(2000); } return (ret); } diff --git a/agents/modules_meshcore/win-deskutils.js b/agents/modules_meshcore/win-deskutils.js new file mode 100644 index 00000000..44e92f47 --- /dev/null +++ b/agents/modules_meshcore/win-deskutils.js @@ -0,0 +1,194 @@ +/* +Copyright 2022 Intel Corporation +@author Bryan Roe + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +// win-deskutils is a utility module that exposes various desktop related features for Windows +// such as MouseTrails Accessability and Windows Desktop Background +// + +// +// MSDN documention for the system call this module relies on can be found at: +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa +// + +var SPI_GETDESKWALLPAPER = 0x0073; +var SPI_SETDESKWALLPAPER = 0x0014; +var SPI_GETMOUSETRAILS = 0x005E; +var SPI_SETMOUSETRAILS = 0x005D; + +var GM = require('_GenericMarshal'); +var user32 = GM.CreateNativeProxy('user32.dll'); +user32.CreateMethod('SystemParametersInfoA'); + +// +// This function is a helper method to dispatch method calls to different user sessions +// +function sessionDispatch(tsid, parent, method, args) +{ + // + // Check to see if the process owner of the current processor is root + // + var sid = undefined; + var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0; + /* + The following is the list of possible values for stype. + If the current process owner is root, we set the stype to user, + because we cannot set/get any properties from this user, we + must switch to a user session.. Default behavior for stype(1) + is that it will context switch to the logged in user. If + this is not intended, then an actual user TSID must be specified, using + ILibProcessPipe_SpawnTypes_SPECIFIED_USER and the actual TSID + ------------------------------------------------------------------------ + ILibProcessPipe_SpawnTypes_DEFAULT = 0, + ILibProcessPipe_SpawnTypes_USER = 1, + ILibProcessPipe_SpawnTypes_WINLOGON = 2, + ILibProcessPipe_SpawnTypes_TERM = 3, + ILibProcessPipe_SpawnTypes_DETACHED = 4, + ILibProcessPipe_SpawnTypes_SPECIFIED_USER = 5, + ILibProcessPipe_SpawnTypes_POSIX_DETACHED = 0x8000 + ------------------------------------------------------------------------ + */ + console.log('stype: ' + stype); + if (stype == 1) + { + if (tsid == null && require('MeshAgent')._tsid != null) + { + stype = 5; // ILibProcessPipe_SpawnTypes_SPECIFIED_USER + sid = require('MeshAgent')._tsid; // If this is set, it was set via user selection UI + } + else + { + sid = tsid; // Set the SID to be whatever was passed in + } + } + + // Spawn a child process in the appropriate user session, and relay the response back via stdout + var mod = Buffer.from(getJSModule('win-deskutils')).toString('base64'); + var prog = "try { addModule('win-deskutils', process.env['win_deskutils']);} catch (x) { } var x;try{x=require('win-deskutils').dispatch('" + parent + "', '" + method + "', " + JSON.stringify(args) + ");console.log(x);}catch(z){console.log(z);process.exit(1);}process.exit(0);"; + var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', Buffer.from(prog).toString('base64')], { type: stype, uid: sid, env: { win_deskutils: getJSModule('win-deskutils') } }); + + child.stdout.str = ''; + child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stderr.on('data', function (c) { }); + child.on('exit', function (c) { this.exitCode = c; }); + child.waitExit(); + if (child.exitCode == 0) + { + return (child.stdout.str.trim()); // If the return code was 0, then relay the response from stdout + } + else + { + throw (child.stdout.str.trim()); // If the return code was nonzero, then the stdout response is the exception that should be bubbled + } +} + +// +// This function gets the path of the windows desktop background of the specified user desktop session +// +function background_get(tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'background', 'get', [])); + } + var v = GM.CreateVariable(1024); + var ret = user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, v._size, v, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to fetch wallpaper'); + } + return (v.String); +} + +// +// This function sets the path for the windows desktop background of the specified user desktop session +// +function background_set(path, tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'background', 'set', [path])); + } + var nb = GM.CreateVariable(path); + var ret = user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, nb._size, nb, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to set wallpaper'); + } + return; +} + +// +// This is a helper function that is called by the child process from sessionDispatch() +// +function dispatch(parent, method, args) +{ + try + { + return (this[parent][method].apply(this, args)); + } + catch (e) + { + console.log('ERROR: ' + e); + throw ('Error occured trying to dispatch: ' + method); + } +} + +// +// This function sets the mousetrail accessibility feature, for the specified user desktop session. +// Setting value 0 or one disables this feature +// Otherwise, value is the number of cursors to render for this feature +// +function mousetrails_set(value, tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'mouse', 'setTrails', [value])); + } + var ret = user32.SystemParametersInfoA(SPI_SETMOUSETRAILS, value, 0, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to fetch wallpaper'); + } +} + +// +// This function returns the number of cursors the mousetrail accessibility feature will render +// A value of 0 or 1 means the feature is disabled, otherwise it is the number of cursors that will be rendered +// +function mousetrails_get(tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'mouse', 'getTrails', [])); + } + var v = GM.CreateVariable(4); + var ret = user32.SystemParametersInfoA(SPI_GETMOUSETRAILS, v._size, v, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to fetch wallpaper'); + } + return (v.toBuffer().readUInt32LE()); +} + +module.exports = { background: { get: background_get, set: background_set } }; +module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set }; +module.exports.dispatch = dispatch; \ No newline at end of file diff --git a/agents/modules_meshcore/win-info.js b/agents/modules_meshcore/win-info.js index 4b0e8f98..dd60eb12 100644 --- a/agents/modules_meshcore/win-info.js +++ b/agents/modules_meshcore/win-info.js @@ -18,28 +18,21 @@ var promise = require('promise'); function qfe() { - var child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', 'qfe', 'list', 'full', '/FORMAT:CSV']); - child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); - child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); - child.waitExit(); - - var lines = child.stdout.str.trim().split('\r\n'); - var keys = lines[0].split(','); - var i, key; - var tokens; - var result = []; - - for (i = 1; i < lines.length; ++i) - { - var obj = {}; - tokens = lines[i].split(','); - for (key = 0; key < keys.length; ++key) - { - if (tokens[key]) { obj[keys[key]] = tokens[key]; } + try { + var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_QuickFixEngineering'); + if (tokens[0]){ + for (var index = 0; index < tokens.length; index++) { + for (var key in tokens[index]) { + if (key.startsWith('__')) delete tokens[index][key]; + } + } + return (tokens); + } else { + return ([]); } - result.push(obj); + } catch (ex) { + return ([]); } - return (result); } function av() { @@ -53,9 +46,23 @@ function av() child.stdin.write('[reflection.Assembly]::LoadWithPartialName("system.core")\r\n'); child.stdin.write('Get-WmiObject -Namespace "root/SecurityCenter2" -Class AntiVirusProduct | '); child.stdin.write('ForEach-Object -Process { '); + child.stdin.write('$matches = [regex]::Matches($_.pathToSignedProductExe, "%(.*?)%"); '); + child.stdin.write('$modifiedPath = $_.pathToSignedProductExe; '); + child.stdin.write('foreach ($match in $matches) { '); + child.stdin.write('$modifiedPath = $modifiedPath -replace [regex]::Escape($match.Value), [System.Environment]::GetEnvironmentVariable($match.Groups[1].Value, "Process") '); + child.stdin.write('} '); + child.stdin.write('$flag = $true; '); + child.stdin.write('if ($modifiedPath -ne "windowsdefender://"){ '); + child.stdin.write('if (-not (Test-Path -Path $modifiedPath -PathType Leaf)) { '); + child.stdin.write('$flag = $false; '); + child.stdin.write('} '); + child.stdin.write('} '); + child.stdin.write('if ($flag -eq $true) { ') child.stdin.write('$Bytes = [System.Text.Encoding]::UTF8.GetBytes($_.displayName); '); child.stdin.write('$EncodedText =[Convert]::ToBase64String($Bytes); '); - child.stdin.write('Write-Host ("{0},{1}" -f $_.productState,$EncodedText); }\r\n'); + child.stdin.write('Write-Output ("{0},{1}" -f $_.productState,$EncodedText); '); + child.stdin.write('} '); + child.stdin.write('}\r\n '); child.stdin.write('exit\r\n'); child.waitExit(); @@ -214,6 +221,14 @@ function installedApps() catch(e)\ {\ }\ + try\ + {\ + val.installdate = reg.QueryKey(reg.HKEY.LocalMachine, 'SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\' + items.subkeys[key], 'InstallDate');\ + if (val.installdate == '') { delete val.installdate; }\ + }\ + catch(e)\ + {\ + }\ result.push(val);\ }\ console.log(JSON.stringify(result,'', 1));process.exit();"; @@ -225,12 +240,33 @@ function installedApps() return (ret); } +function defender(){ + var promise = require('promise'); + var ret = new promise(function (a, r) { this._resolve = a; this._reject = r; }); + ret.child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {}); + ret.child.promise = ret; + ret.child.stdout.str = ''; ret.child.stdout.on('data', function (c) { this.str += c.toString(); }); + ret.child.stderr.str = ''; ret.child.stderr.on('data', function (c) { this.str += c.toString(); }); + ret.child.stdin.write('Get-MpComputerStatus | Select-Object RealTimeProtectionEnabled,IsTamperProtected | ConvertTo-JSON\r\n'); + ret.child.stdin.write('exit\r\n'); + ret.child.on('exit', function (c) { + if (this.stdout.str == '') { this.promise._resolve({}); return; } + try { + var abc = JSON.parse(this.stdout.str.trim()); + this.promise._resolve({ RealTimeProtection: abc.RealTimeProtectionEnabled, TamperProtected: abc.IsTamperProtected }); + } catch (ex) { + this.promise._resolve({}); return; + } + }); + return (ret); +} + if (process.platform == 'win32') { - module.exports = { qfe: qfe, av: av, defrag: defrag, pendingReboot: pendingReboot, installedApps: installedApps }; + module.exports = { qfe: qfe, av: av, defrag: defrag, pendingReboot: pendingReboot, installedApps: installedApps, defender: defender }; } else { var not_supported = function () { throw (process.platform + ' not supported'); }; - module.exports = { qfe: not_supported, av: not_supported, defrag: not_supported, pendingReboot: not_supported, installedApps: not_supported }; + module.exports = { qfe: not_supported, av: not_supported, defrag: not_supported, pendingReboot: not_supported, installedApps: not_supported, defender: not_supported }; } \ No newline at end of file diff --git a/agents/modules_meshcore/win-volumes.js b/agents/modules_meshcore/win-volumes.js index e0e11276..59e87c1a 100644 --- a/agents/modules_meshcore/win-volumes.js +++ b/agents/modules_meshcore/win-volumes.js @@ -39,17 +39,90 @@ function getVolumes() { ret[v[i].DeviceID] = trimObject(v[i]); } - - v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume'); - for (i in v) - { - var tmp = trimObject(v[i]); - for (var k in tmp) + try { + v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume'); + for (i in v) { - ret[tmp.DeviceID][k] = tmp[k]; + var tmp = trimObject(v[i]); + for (var k in tmp) + { + ret[tmp.DeviceID][k] = tmp[k]; + } } - } + } catch (ex) { } return (ret); } -module.exports = { getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } } }; \ No newline at end of file +function windows_volumes() +{ + var promise = require('promise'); + var p1 = new promise(function (res, rej) { this._res = res; this._rej = rej; }); + var ret = {}; + var values = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_LogicalDisk', ['DeviceID', 'VolumeName', 'FileSystem', 'Size', 'FreeSpace', 'DriveType']); + if(values[0]){ + for (var i = 0; i < values.length; ++i) { + var drive = values[i]['DeviceID'].slice(0,-1); + ret[drive] = { + name: (values[i]['VolumeName'] ? values[i]['VolumeName'] : ""), + type: (values[i]['FileSystem'] ? values[i]['FileSystem'] : "Unknown"), + size: (values[i]['Size'] ? values[i]['Size'] : 0), + sizeremaining: (values[i]['FreeSpace'] ? values[i]['FreeSpace'] : 0), + removable: (values[i]['DriveType'] == 2), + cdrom: (values[i]['DriveType'] == 5) + }; + } + } + try { + values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume', ['DriveLetter','ConversionStatus','ProtectionStatus']); + if(values[0]){ + for (var i = 0; i < values.length; ++i) { + var drive = values[i]['DriveLetter'].slice(0,-1); + var statuses = { + 0: 'FullyDecrypted', + 1: 'FullyEncrypted', + 2: 'EncryptionInProgress', + 3: 'DecryptionInProgress', + 4: 'EncryptionPaused', + 5: 'DecryptionPaused' + }; + ret[drive].volumeStatus = statuses.hasOwnProperty(values[i].ConversionStatus) ? statuses[values[i].ConversionStatus] : 'FullyDecrypted'; + ret[drive].protectionStatus = (values[i].ProtectionStatus == 0 ? 'Off' : (values[i].ProtectionStatus == 1 ? 'On' : 'Unknown')); + try { + var foundIDMarkedLine = false, foundMarkedLine = false, identifier = '', password = ''; + var keychild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'manage-bde -protectors -get ' + drive + ': -Type recoverypassword'], {}); + keychild.stdout.str = ''; keychild.stdout.on('data', function (c) { this.str += c.toString(); }); + keychild.waitExit(); + var lines = keychild.stdout.str.trim().split('\r\n'); + for (var x = 0; x < lines.length; x++) { // Loop each line + var abc = lines[x].trim(); + var englishidpass = (abc !== '' && abc.includes('Numerical Password:')); // English ID + var germanidpass = (abc !== '' && abc.includes('Numerisches Kennwort:')); // German ID + var frenchidpass = (abc !== '' && abc.includes('Mot de passe num')); // French ID + var englishpass = (abc !== '' && abc.includes('Password:') && !abc.includes('Numerical Password:')); // English Password + var germanpass = (abc !== '' && abc.includes('Kennwort:') && !abc.includes('Numerisches Kennwort:')); // German Password + var frenchpass = (abc !== '' && abc.includes('Mot de passe :') && !abc.includes('Mot de passe num')); // French Password + if (englishidpass || germanidpass || frenchidpass|| englishpass || germanpass || frenchpass) { + var nextline = lines[x + 1].trim(); + if (x + 1 < lines.length && (nextline !== '' && (nextline.startsWith('ID:') || nextline.startsWith('ID :')) )) { + identifier = nextline.replace('ID:','').replace('ID :', '').trim(); + foundIDMarkedLine = true; + }else if (x + 1 < lines.length && nextline !== '') { + password = nextline; + foundMarkedLine = true; + } + } + } + ret[drive].identifier = (foundIDMarkedLine ? identifier : ''); // Set Bitlocker Identifier + ret[drive].recoveryPassword = (foundMarkedLine ? password : ''); // Set Bitlocker Password + } catch(ex) { } // just carry on as we cant get bitlocker key + } + } + p1._res(ret); + } catch (ex) { p1._res(ret); } // just return volumes as cant get encryption/bitlocker + return (p1); +} + +module.exports = { + getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } }, + volumes_promise: windows_volumes +}; \ No newline at end of file diff --git a/agents/recoverycore.js b/agents/recoverycore.js index 169b170c..5d9f13bc 100644 --- a/agents/recoverycore.js +++ b/agents/recoverycore.js @@ -485,8 +485,8 @@ function windows_execve(name, agentfilename, sessionid) { var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true }); var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize); var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true }); - var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' + - ' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + cwd + agentfilename + '.update.exe"', { wide: true }); + var arg2 = require('_GenericMarshal').CreateVariable('/C net stop "' + name + '" & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' + + ' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & net start "' + name + '" & erase "' + cwd + agentfilename + '.update.exe"', { wide: true }); if (name == null) { diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js index d9522c3a..689250d0 100644 --- a/amt/amt-wsman-comm.js +++ b/amt/amt-wsman-comm.js @@ -274,7 +274,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected); } else { // Direct connect with TLS - var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; + var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false }; if (obj.xtlsMethod != 0) { options.secureProtocol = 'TLSv1_method'; } if (obj.xtlsoptions) { if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; } diff --git a/amtmanager.js b/amtmanager.js index dd792aca..10e19647 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -707,7 +707,15 @@ module.exports.CreateAmtManager = function (parent) { dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM if (typeof stack.wsman.comm.amtVersion == 'string') { // Set the Intel AMT version using the HTTP header if present var verSplit = stack.wsman.comm.amtVersion.split('.'); - if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); } + if (verSplit.length >= 2) { + dev.aquired.version = verSplit[0] + '.' + verSplit[1]; + dev.aquired.majorver = parseInt(verSplit[0]); + dev.aquired.minorver = parseInt(verSplit[1]); + if (verSplit.length >= 3) { + dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; + dev.aquired.maintenancever = parseInt(verSplit[2]); + } + } } dev.aquired.realm = stack.wsman.comm.digestRealm; dev.aquired.user = dev.intelamt.user = stack.wsman.comm.user; @@ -750,7 +758,8 @@ module.exports.CreateAmtManager = function (parent) { // Start power polling if not connected to LMS var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); } ppfunc.dev = dev; - dev.polltimer = new setTimeout(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds. + if(dev.polltimer){ clearInterval(dev.polltimer); delete dev.polltimer; } + dev.polltimer = new setInterval(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds. fetchPowerState(dev); } else { // For LMS connections, close now. @@ -930,8 +939,8 @@ module.exports.CreateAmtManager = function (parent) { if (response.Body.OSPowerSavingState == 2) { meshPowerState = 1; } // Fully powered (S0); else if (response.Body.OSPowerSavingState == 3) { meshPowerState = 2; } // Modern standby (We are going to call this S1); - // Set OS power state - if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), 4, meshPowerState, null, { name: dev.name }); } + // Set OS power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN + if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); } }); } else { // Convert the power state @@ -940,13 +949,13 @@ module.exports.CreateAmtManager = function (parent) { var meshPowerState = -1, powerConversionTable = [-1, -1, 1, 2, 3, 6, 6, 5, 6]; if (powerstate < powerConversionTable.length) { meshPowerState = powerConversionTable[powerstate]; } else { powerstate = 6; } - // Set power state - if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), 4, meshPowerState, null, { name: dev.name }); } + // Set power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN + if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); } } }); } - // Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL + // Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE function performPowerAction(nodeid, action) { console.log('performPowerAction', nodeid, action); var devices = obj.amtDevices[nodeid]; @@ -961,7 +970,7 @@ module.exports.CreateAmtManager = function (parent) { // Action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { } } else { - // 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL + // 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE dev.amtstack.BatchEnum(null, ['*AMT_BootSettingData'], performAdvancedPowerActionResponse); } } @@ -994,8 +1003,8 @@ module.exports.CreateAmtManager = function (parent) { // Ready boot parameters bootSettingData['BIOSSetup'] = ((action >= 11) && (action <= 14)); bootSettingData['UseSOL'] = ((action >= 13) && (action <= 14)); - if ((action == 11) || (action == 13)) { dev.powerAction = 2; } // Power on - if ((action == 12) || (action == 14)) { dev.powerAction = 10; } // Reset + if ((action == 11) || (action == 13) || (action == 15)) { dev.powerAction = 2; } // Power on + if ((action == 12) || (action == 14) || (action == 16)) { dev.powerAction = 10; } // Reset // Set boot parameters dev.amtstack.Put('AMT_BootSettingData', bootSettingData, function (stack, name, response, status, tag) { @@ -1006,7 +1015,8 @@ module.exports.CreateAmtManager = function (parent) { const dev = stack.dev; if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error // Set boot order - dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(null, function (stack, name, response, status) { + var bootDevice = (action === 15 || action === 16) ? '
http://schemas.xmlsoap.org/ws/2004/08/addressing
http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSettingIntel(r) AMT: Force PXE Boot' : null; + dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(bootDevice, function (stack, name, response, status) { const dev = stack.dev; if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error // Perform power action @@ -1059,7 +1069,7 @@ module.exports.CreateAmtManager = function (parent) { if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; } // Check if this Intel AMT device supports OCR - if (responses['AMT_PublicKeyCertificate'].responses['ForceUEFIHTTPSBoot'] !== true) { + if (responses['AMT_BootCapabilities'].response['ForceUEFIHTTPSBoot'] !== true) { dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return; } @@ -1089,11 +1099,14 @@ module.exports.CreateAmtManager = function (parent) { // Generate the one-time URL. var cookie = obj.parent.encodeCookie({ a: 'f', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey) - var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.iso'; + var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.efi'; delete dev.ocrfile; // Generate the boot data for OCR with URL var r = response.Body; + r['BIOSPause'] = false; + r['BIOSSetup'] = false; + r['EnforceSecureBoot'] = false; r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64'); r['UefiBootNumberOfParams'] = 3; r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR) @@ -1114,8 +1127,7 @@ module.exports.CreateAmtManager = function (parent) { dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) { if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request. if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; } - var bootSource = 'Force OCR UEFI HTTPS Boot'; - dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder((bootSource == null) ? bootSource : '
http://schemas.xmlsoap.org/ws/2004/08/addressing
http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSettingIntel(r) AMT: ' + bootSource + '', function (stack, name, response, status) { + dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder('
http://schemas.xmlsoap.org/ws/2004/08/addressing
http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSettingIntel(r) AMT: Force OCR UEFI HTTPS Boot', function (stack, name, response, status) { if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request. if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; } dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up @@ -1318,7 +1330,7 @@ module.exports.CreateAmtManager = function (parent) { } // Figure out what index is local & remote - var localNdx = ((dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx); + var localNdx = ((dev.policy != null) && (dev.policy.tlsSettings != null) && (dev.policy.tlsSettings[0] != null) && (dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx); // Remote TLS settings var xxTlsSettings2 = Clone(dev.policy.tlsSettings); @@ -2620,7 +2632,14 @@ module.exports.CreateAmtManager = function (parent) { if (domain && domain.amtmanager && (domain.amtmanager.tlsacmactivation == true)) { TlsAcmActivation = true; } // Check Intel AMT version - if (typeof dev.intelamt.ver == 'string') { var verSplit = dev.intelamt.ver.split('.'); if (verSplit.length >= 3) { dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); } } + if (typeof dev.intelamt.ver == 'string') { + var verSplit = dev.intelamt.ver.split('.'); + if (verSplit.length >= 2) { + dev.aquired.majorver = parseInt(verSplit[0]); + dev.aquired.minorver = parseInt(verSplit[1]); + if (verSplit.length >= 3) { dev.aquired.maintenancever = parseInt(verSplit[2]); } + } + } // If this is Intel AMT 14 or better and allowed, we are going to attempt a host-based end-to-end TLS activation. if (TlsAcmActivation && (dev.aquired.majorver >= 14)) { @@ -2676,7 +2695,15 @@ module.exports.CreateAmtManager = function (parent) { dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') { var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.'); - if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); } + if (verSplit.length >= 2) { + dev.aquired.version = verSplit[0] + '.' + verSplit[1]; + dev.aquired.majorver = parseInt(verSplit[0]); + dev.aquired.minorver = parseInt(verSplit[1]); + if (verSplit.length >= 3) { + dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; + dev.aquired.maintenancever = parseInt(verSplit[2]); + } + } } if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) { dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix; @@ -2811,8 +2838,10 @@ module.exports.CreateAmtManager = function (parent) { var vs = getInstance(amtlogicalelements, 'AMT')['VersionString']; if (vs != null) { dev.aquired.version = vs; - dev.aquired.versionmajor = parseInt(dev.aquired.version.split('.')[0]); - dev.aquired.versionminor = parseInt(dev.aquired.version.split('.')[1]); + version = dev.aquired.version.split('.') + dev.aquired.versionmajor = parseInt(version[0]); + dev.aquired.versionminor = parseInt(version[1]); + if (version.length > 2) { dev.aquired.versionmaintenance = parseInt(version[2]); } } } } @@ -2820,10 +2849,14 @@ module.exports.CreateAmtManager = function (parent) { // Fetch the Intel AMT version from HTTP stack if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) { var s = stack.wsman.comm.amtVersion.split('.'); - if (s.length >= 3) { - dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2]; + if (s.length >= 2) { + dev.aquired.version = s[0] + '.' + s[1] + '.'; dev.aquired.versionmajor = parseInt(s[0]); dev.aquired.versionminor = parseInt(s[1]); + if (s.length >= 3) { + dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2]; + dev.aquired.versionmaintenance = parseInt(s[2]); + } } } diff --git a/amtprovisioningserver.js b/amtprovisioningserver.js index 84a07df9..d31b7b83 100644 --- a/amtprovisioningserver.js +++ b/amtprovisioningserver.js @@ -201,8 +201,10 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) { var vs = getInstance(amtlogicalelements, 'AMT')['VersionString']; if (vs != null) { dev.aquired.version = vs; - dev.aquired.versionmajor = parseInt(dev.aquired.version.split('.')[0]); - dev.aquired.versionminor = parseInt(dev.aquired.version.split('.')[1]); + const versionSplit = parseInt(dev.aquired.version.split('.')); + dev.aquired.versionmajor = parseInt(versionSplit[0]); + dev.aquired.versionminor = parseInt(versionSplit[1]); + if (versionSplit.length >= 3) { dev.aquired.versionmaintenance = parseInt(versionSplit[2]); } } } } @@ -210,10 +212,14 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) { // Fetch the Intel AMT version from HTTP stack if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) { var s = stack.wsman.comm.amtVersion.split('.'); - if (s.length >= 3) { - dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2]; + if (s.length >= 2) { + dev.aquired.version = s[0] + '.' + s[1]; dev.aquired.versionmajor = parseInt(s[0]); dev.aquired.versionminor = parseInt(s[1]); + if (s.length >= 3) { + dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2]; + dev.aquired.versionmaintenance = parseInt(s[2]); + } } } diff --git a/amtscanner.js b/amtscanner.js index 941aef7e..cdce1f54 100644 --- a/amtscanner.js +++ b/amtscanner.js @@ -362,8 +362,8 @@ module.exports.CreateAmtScanner = function (parent) { if (oldVer == newVer) return false; // Versions are same already, don't update. if (newVer == undefined || newVer == null) return false; // New version is bad, don't update it. if (oldVer == undefined || oldVer == null) return true; // Old version is no good anyway, update it. - var oldVerArr = oldVer.split('.'); - var newVerArr = newVer.split('.'); + var oldVerArr = oldVer.toString().split('.'); + var newVerArr = newVer.toString().split('.'); if ((oldVerArr.length < 2) || (newVerArr.length < 2)) return false; if ((oldVerArr[0] != newVerArr[0]) || (oldVerArr[1] != newVerArr[1])) return true; if (newVerArr.length > oldVerArr.length) return true; diff --git a/apprelays.js b/apprelays.js index 7f5444c5..cd6bc5fa 100644 --- a/apprelays.js +++ b/apprelays.js @@ -1,4 +1,4 @@ -/** +/** * @description MeshCentral MSTSC & SSH relay * @author Ylian Saint-Hilaire & Bryan Roe * @copyright Intel Corporation 2018-2022 @@ -458,7 +458,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) { const protocol = (args.tlsoffload) ? 'ws' : 'wss'; var domainadd = ''; if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } - const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + cookie; // Protocol 14 is Web-TCP + var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + cookie; // Protocol 14 is Web-TCP if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. parent.parent.parent.debug('relay', 'TCP: Connection websocket to ' + url); obj.wsClient = new WebSocket(url, options); @@ -717,9 +717,10 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) { } } } - else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i, header[i]); } // Set the headers if not blocked + else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i.trim(), header[i]); } // Set the headers if not blocked } - obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future + // Dont set any Content-Security-Policy at all because some applications like Node-Red, access external websites from there javascript which would be forbidden by the below CSP + //obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future //obj.res.set('Content-Security-Policy', "default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';"); // Set an "allow all" policy, see if the can restrict this in the future obj.res.set('Cache-Control', 'no-store'); // Tell the browser not to cache the responses since since the relay port can be used for many relays } @@ -820,7 +821,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { obj.relaySocket = socket; obj.relaySocket.pause(); obj.relaySocket.on('data', function (chunk) { // Make sure to handle flow control. - if (obj.relayActive == true) { obj.relaySocket.pause(); obj.wsClient.send(chunk, function () { obj.relaySocket.resume(); }); } + if (obj.relayActive == true) { obj.relaySocket.pause(); if (obj.wsClient != null) { obj.wsClient.send(chunk, function () { obj.relaySocket.resume(); }); } } }); obj.relaySocket.on('end', function () { obj.close(); }); obj.relaySocket.on('error', function (err) { obj.close(); }); @@ -842,22 +843,21 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { obj.relaySocket.resume(); } } else { - if (typeof data == 'string') { - // Forward any ping/pong commands to the browser - var cmd = null; - try { cmd = JSON.parse(data); } catch (ex) { } + try { // Forward any ping/pong commands to the browser + var cmd = JSON.parse(data); if ((cmd != null) && (cmd.ctrlChannel == '102938')) { if (cmd.type == 'ping') { send(['ping']); } else if (cmd.type == 'pong') { send(['pong']); } } return; + } catch (ex) { // You are not JSON data so just send over relaySocket + obj.wsClient._socket.pause(); + try { + obj.relaySocket.write(data, function () { + if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } } + }); + } catch (ex) { console.log(ex); obj.close(); } } - obj.wsClient._socket.pause(); - try { - obj.relaySocket.write(data, function () { - if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } } - }); - } catch (ex) { console.log(ex); obj.close(); } } }); obj.wsClient.on('close', function () { parent.parent.debug('relay', 'RDP: Relay websocket closed'); obj.close(); }); @@ -984,6 +984,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { if ((node == null) || (visible == false) || ((rights & MESHRIGHT_REMOTECONTROL) == 0)) { obj.close(); return; } if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_REMOTEVIEWONLY) != 0)) { obj.viewonly = true; } if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_DESKLIMITEDINPUT) != 0)) { obj.limitedinput = true; } + node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials obj.mtype = node.mtype; // Store the device group type obj.meshid = node.meshid; // Store the MeshID @@ -1046,7 +1047,11 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { if ((k == 14) || (k == 28)) { ok = true; } // Enter and backspace if (ok == false) return; } - if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventScancode(msg[1], msg[2]); } break; + var extended = false; + var extendedkeys = [57419,57421,57416,57424,57426,57427,57417,57425,57372,57397,57415,57423,57373,57400,57399]; + // left,right,up,down,insert,delete,pageup,pagedown,numpadenter,numpaddivide,home,end,controlright,altright,printscreen + if (extendedkeys.includes(msg[1])) extended=true; + if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventScancode(msg[1], msg[2], extended); } break; } case 'unicode': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventUnicode(msg[1], msg[2]); } break; } case 'utype': { @@ -1210,7 +1215,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { const protocol = (args.tlsoffload) ? 'ws' : 'wss'; var domainadd = ''; if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } - const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + obj.xcookie; // Protocol 11 is Web-SSH + var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + obj.xcookie; // Protocol 11 is Web-SSH if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. parent.parent.debug('relay', 'SSH: Connection websocket to ' + url); obj.wsClient = new WebSocket(url, options); @@ -1277,16 +1282,14 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { ws._socket.resume(); } } else { - if (typeof data == 'string') { - // Forward any ping/pong commands to the browser + try { // Forward any ping/pong commands to the browser var cmd = null; - try { cmd = JSON.parse(data); } catch (ex) { } + cmd = JSON.parse(data); if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); } return; + } catch(ex) { // Relay WS --> SSH instead + if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } } } - - // Relay WS --> SSH - if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } } } }); obj.wsClient.on('close', function () { parent.parent.debug('relay', 'SSH: Relay websocket closed'); obj.close(); }); @@ -1314,7 +1317,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { // Check if we have SSH credentials for this device parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { if ((err != null) || (nodes == null) || (nodes.length != 1)) return; - const node = nodes[0]; + const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[obj.userid] == null) || (typeof node.ssh[obj.userid].u != 'string') || ((typeof node.ssh[obj.userid].p != 'string') && (typeof node.ssh[obj.userid].k != 'string'))) { // Send a request for SSH authentication try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { } @@ -1362,7 +1365,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { obj.termSize = msg; parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { if ((err != null) || (nodes == null) || (nodes.length != 1)) return; - const node = nodes[0]; + const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials if (node.ssh != null) { obj.username = node.ssh.u; obj.privateKey = node.ssh.k; @@ -1404,7 +1407,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) { parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { if (obj.cookie == null) return; // obj has been cleaned up, just exit. if ((err != null) || (nodes == null) || (nodes.length != 1)) { parent.parent.debug('relay', 'SSH: Invalid device'); obj.close(); } - const node = nodes[0]; + const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials obj.nodeid = node._id; // Store the NodeID obj.meshid = node.meshid; // Store the MeshID obj.mtype = node.mtype; // Store the device group type @@ -1549,7 +1552,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u const protocol = (args.tlsoffload) ? 'ws' : 'wss'; var domainadd = ''; if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } - const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + authCookie // Protocol 11 is Web-SSH + var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + authCookie // Protocol 11 is Web-SSH if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. parent.parent.debug('relay', 'SSH: Connection websocket to ' + url); obj.wsClient = new WebSocket(url, options); @@ -1617,16 +1620,14 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u ws._socket.resume(); } } else { - if (typeof data == 'string') { - // Forward any ping/pong commands to the browser + try { // Forward any ping/pong commands to the browser var cmd = null; - try { cmd = JSON.parse(data); } catch (ex) { } + cmd = JSON.parse(data); if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { try { obj.ws.send(data); } catch (ex) { console.log(ex); } } return; + } catch (ex) { // Relay WS --> SSH + if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } } } - - // Relay WS --> SSH - if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } } } }); obj.wsClient.on('close', function () { @@ -1739,6 +1740,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) { if (obj.ws == null) return; // obj has been cleaned up, just exit. + node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials // Check permissions if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights @@ -1903,7 +1905,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user const protocol = (args.tlsoffload) ? 'ws' : 'wss'; var domainadd = ''; if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } - const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=13&auth=' + authCookie // Protocol 13 is Web-SSH-Files + var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=13&auth=' + authCookie // Protocol 13 is Web-SSH-Files if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. parent.parent.debug('relay', 'SSH: Connection websocket to ' + url); obj.wsClient = new WebSocket(url, options); @@ -1965,16 +1967,15 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user ws._socket.resume(); } } else { - if (typeof data == 'string') { + try { // Forward any ping/pong commands to the browser var cmd = null; - try { cmd = JSON.parse(data); } catch (ex) { } + cmd = JSON.parse(data); if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); } return; + } catch (ex) { // Relay WS --> SSH + if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } } } - - // Relay WS --> SSH - if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } } } }); obj.wsClient.on('close', function () { @@ -2269,6 +2270,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) { if (obj.ws == null) return; // obj has been cleaned up, just exit. + node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials // Check permissions if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights diff --git a/authenticode.js b/authenticode.js index 821cf7ae..5f0bd441 100644 --- a/authenticode.js +++ b/authenticode.js @@ -298,7 +298,7 @@ function createAuthenticodeHandler(path) { for (var i = 0; i < obj.header.coff.numberOfSections; i++) { var section = {}; buf = readFileSlice(obj.header.SectionHeadersPtr + (i * 40), 40); - if (buf[0] != 46) { obj.close(); return false; }; // Name of the section must start with a dot. If not, something is wrong. + if ((buf[0] != 46) && (buf[0] != 95)) { obj.close(); return false; }; // Name of the section must start with a dot or underscore. If not, something is wrong. var sectionName = buf.slice(0, 8).toString().trim('\0'); var j = sectionName.indexOf('\0'); if (j >= 0) { sectionName = sectionName.substring(0, j); } // Trim any trailing zeroes @@ -1566,7 +1566,11 @@ function createAuthenticodeHandler(path) { options.protocol = timeServerUrl.protocol; options.hostname = timeServerUrl.hostname; options.path = timeServerUrl.pathname; - options.port = ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port)); + let http = require("http") + if (options.protocol === "https:"){ + http = require("https") + } + options.port = ((timeServerUrl.port == '') ? (options.protocol === "https:" ? 443 : 80) : parseInt(timeServerUrl.port)); if (options.proxy == null) { // No proxy needed @@ -1584,7 +1588,7 @@ function createAuthenticodeHandler(path) { // Set up the request var responseAccumulator = ''; - var req = require('http').request(options, function (res) { + var req = http.request(options, function (res) { res.setEncoding('utf8'); res.on('data', function (chunk) { responseAccumulator += chunk; }); res.on('end', function () { func(null, responseAccumulator); }); @@ -1605,12 +1609,12 @@ function createAuthenticodeHandler(path) { proxyOptions.protocol = proxyUrl.protocol; proxyOptions.hostname = proxyUrl.hostname; proxyOptions.path = options.hostname + ':' + options.port; - proxyOptions.port = ((proxyUrl.port == '') ? 80 : parseInt(proxyUrl.port)); + proxyOptions.port = ((proxyUrl.port == '') ? (options.protocol === "https:" ? 443 : 80) : parseInt(proxyUrl.port)); } // Set up the proxy request var responseAccumulator = ''; - var req = require('http').request(proxyOptions); + var req = http.request(proxyOptions); req.on('error', function (err) { func('' + err); }); req.on('connect', function (res, socket, head) { // Make a request over the HTTP tunnel diff --git a/certoperations.js b/certoperations.js index fcc4c840..50c92f2a 100644 --- a/certoperations.js +++ b/certoperations.js @@ -262,7 +262,10 @@ module.exports.CertificateOperations = function (parent) { acmconfig.cn = certCommonName.value; } } - + if(r.certs[0].md){ + acmconfig.hashAlgorithm = r.certs[0].md.algorithm; + } + delete acmconfig.cert; delete acmconfig.certpass; acmconfig.certs = orderedCerts; @@ -633,9 +636,16 @@ module.exports.CertificateOperations = function (parent) { }; // Return the SHA384 hash of the certificate public key - obj.getPublicKeyHashBinary = function (cert) { - var publickey = obj.pki.certificateFromPem(cert).publicKey; - return obj.pki.getPublicKeyFingerprint(publickey, { encoding: 'binary', md: obj.forge.md.sha384.create() }); + obj.getPublicKeyHashBinary = function (pem) { + const { X509Certificate } = require('crypto'); + if (X509Certificate == null) { + // This version of NodeJS (Settings->Cert when using a wildcard certificate."); process.exit(0); return; } @@ -1318,20 +1408,15 @@ module.exports.CertificateOperations = function (parent) { // Perform any general operation obj.acceleratorPerformOperation = function (operation, data, tag, func) { - if (acceleratorTotalCount <= 1) { - // No accelerators available - require(program).processMessage({ action: operation, data: data, tag: tag, func: func }); + var acc = obj.getAccelerator(); + if (acc == null) { + // Add to pending accelerator workload + acceleratorPerformSignaturePushFuncCall++; + pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func }); } else { - var acc = obj.getAccelerator(); - if (acc == null) { - // Add to pending accelerator workload - acceleratorPerformSignaturePushFuncCall++; - pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func }); - } else { - // Send to accelerator now - acceleratorPerformSignatureRunFuncCall++; - acc.send(acc.x = { action: operation, data: data, tag: tag, func: func }); - } + // Send to accelerator now + acceleratorPerformSignatureRunFuncCall++; + acc.send(acc.x = { action: operation, data: data, tag: tag, func: func }); } }; diff --git a/common.js b/common.js index 68403aaf..f1fdf105 100644 --- a/common.js +++ b/common.js @@ -142,22 +142,39 @@ module.exports.zeroPad = function(num, c) { if (c == null) { c = 2; } var s = '0 // Lowercase all the names in a object recursively // Allow for exception keys, child of exceptions will not get lower-cased. -module.exports.objKeysToLower = function (obj, exceptions) { +// Exceptions is an array of "keyname" or "parent\keyname" +module.exports.objKeysToLower = function (obj, exceptions, parent) { for (var i in obj) { - if ((typeof obj[i] == 'object') && ((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1))) { module.exports.objKeysToLower(obj[i], exceptions); } // LowerCase all key names in the child object + if ((typeof obj[i] == 'object') && + ((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1) && ((parent == null) || (exceptions.indexOf(parent.toLowerCase() + '/' + i.toLowerCase()) == -1))) + ) { + module.exports.objKeysToLower(obj[i], exceptions, i); // LowerCase all key names in the child object + } if (i.toLowerCase() !== i) { obj[i.toLowerCase()] = obj[i]; delete obj[i]; } // LowerCase all key names } return obj; }; -// Escape and unescape feild names so there are no invalid characters for MongoDB -module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24'); }; -module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); }; +// Escape and unescape field names so there are no invalid characters for MongoDB/NeDB ("$", ",", ".", see https://github.com/seald/nedb/tree/master?tab=readme-ov-file#inserting-documents) +module.exports.escapeFieldName = function (name) { if ((name.indexOf(',') == -1) && (name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24').split(',').join('%2C'); }; +module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2C').join(',').split('%2E').join('.').split('%24').join('$').split('%25').join('%'); }; -// Escape all links -module.exports.escapeLinksFieldNameEx = function (docx) { if (docx.links == null) { return docx; } var doc = Object.assign({}, docx); doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } return doc; }; -module.exports.escapeLinksFieldName = function (docx) { var doc = Object.assign({}, docx); if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } } return doc; }; -module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; }; +// Escape all links, SSH and RDP usernames +// This is required for databases like NeDB that don't accept "." or "," as part of a field name. +module.exports.escapeLinksFieldNameEx = function (docx) { if ((docx.links == null) && (docx.ssh == null) && (docx.rdp == null)) { return docx; } return module.exports.escapeLinksFieldName(docx); }; +module.exports.escapeLinksFieldName = function (docx) { + var doc = Object.assign({}, docx); + if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } } + if (doc.ssh != null) { doc.ssh = Object.assign({}, doc.ssh); for (var i in doc.ssh) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.ssh[ue] = doc.ssh[i]; delete doc.ssh[i]; } } } + if (doc.rdp != null) { doc.rdp = Object.assign({}, doc.rdp); for (var i in doc.rdp) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.rdp[ue] = doc.rdp[i]; delete doc.rdp[i]; } } } + return doc; +}; +module.exports.unEscapeLinksFieldName = function (doc) { + if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } + if (doc.ssh != null) { for (var j in doc.ssh) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.ssh[ue] = doc.ssh[j]; delete doc.ssh[j]; } } } + if (doc.rdp != null) { for (var j in doc.rdp) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.rdp[ue] = doc.rdp[j]; delete doc.rdp[j]; } } } + return doc; +}; //module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; }; module.exports.unEscapeAllLinksFieldName = function (docs) { for (var i in docs) { docs[i] = module.exports.unEscapeLinksFieldName(docs[i]); } return docs; }; @@ -317,6 +334,11 @@ module.exports.meshServerRightsArrayToNumber = function (val) { if (r == 'locked') { newAccRights |= 32; } if (r == 'nonewgroups') { newAccRights |= 64; } if (r == 'notools') { newAccRights |= 128; } + if (r == 'usergroups') { newAccRights |= 256; } + if (r == 'recordings') { newAccRights |= 512; } + if (r == 'locksettings') { newAccRights |= 1024; } + if (r == 'allevents') { newAccRights |= 2048; } + if (r == 'nonewdevices') { newAccRights |= 4096; } } return newAccRights; } @@ -369,4 +391,32 @@ module.exports.moveOldFiles = function (filelist) { for (var i in filelist) { if (fs.existsSync(filelist[i] + oldFileExt) == true) { extOk = false; } } } while (extOk == false); for (var i in filelist) { try { fs.renameSync(filelist[i], filelist[i] + oldFileExt); } catch (ex) { } } +} + +// Convert strArray to Array, returns array if strArray or null if any other type +module.exports.convertStrArray = function (object, split) { + if (split && typeof object === 'string') { + return object.split(split) + } else if (typeof object === 'string') { + return Array(object); + } else if (Array.isArray(object)) { + return object + } else { + return [] + } +} + +module.exports.uniqueArray = function (a) { + var seen = {}; + var out = []; + var len = a.length; + var j = 0; + for(var i = 0; i < len; i++) { + var item = a[i]; + if(seen[item] !== 1) { + seen[item] = 1; + out[j++] = item; + } + } + return out; } \ No newline at end of file diff --git a/db.js b/db.js index ea8ecc6e..81ea222c 100644 --- a/db.js +++ b/db.js @@ -30,8 +30,33 @@ module.exports.CreateDB = function (parent, func) { var Datastore = null; var expireEventsSeconds = (60 * 60 * 24 * 20); // By default, expire events after 20 days (1728000). (Seconds * Minutes * Hours * Days) var expirePowerEventsSeconds = (60 * 60 * 24 * 10); // By default, expire power events after 10 days (864000). (Seconds * Minutes * Hours * Days) - var expireServerStatsSeconds = (60 * 60 * 24 * 30); // By default, expire power events after 30 days (2592000). (Seconds * Minutes * Hours * Days) + var expireServerStatsSeconds = (60 * 60 * 24 * 30); // By default, expire server stats after 30 days (2592000). (Seconds * Minutes * Hours * Days) const common = require('./common.js'); + const path = require('path'); + const fs = require('fs'); + const DB_NEDB = 1, DB_MONGOJS = 2, DB_MONGODB = 3,DB_MARIADB = 4, DB_MYSQL = 5, DB_POSTGRESQL = 6, DB_ACEBASE = 7, DB_SQLITE = 8; + const DB_LIST = ['None', 'NeDB', 'MongoJS', 'MongoDB', 'MariaDB', 'MySQL', 'PostgreSQL', 'AceBase', 'SQLite']; //for the info command + let databaseName = 'meshcentral'; + let datapathParentPath = path.dirname(parent.datapath); + let datapathFoldername = path.basename(parent.datapath); + const SQLITE_AUTOVACUUM = ['none', 'full', 'incremental']; + const SQLITE_SYNCHRONOUS = ['off', 'normal', 'full', 'extra']; + obj.sqliteConfig = { + maintenance: '', + startupVacuum: false, + autoVacuum: 'full', + incrementalVacuum: 100, + journalMode: 'delete', + journalSize: 4096000, + synchronous: 'full', + }; + obj.performingBackup = false; + const BACKUPFAIL_ZIPCREATE = 0x0001; + const BACKUPFAIL_ZIPMODULE = 0x0010; + const BACKUPFAIL_DBDUMP = 0x0100; + obj.backupStatus = 0x0; + obj.newAutoBackupFile = null; + obj.newDBDumpFile = null; obj.identifier = null; obj.dbKey = null; obj.dbRecordsEncryptKey = null; @@ -105,16 +130,17 @@ module.exports.CreateDB = function (parent, func) { // Perform database maintenance obj.maintenance = function () { - if (obj.databaseType == 1) { // NeDB will not remove expired records unless we try to access them. This will force the removal. + parent.debug('db', 'Entering database maintenance'); + if (obj.databaseType == DB_NEDB) { // NeDB will not remove expired records unless we try to access them. This will force the removal. obj.eventsfile.remove({ time: { '$lt': new Date(Date.now() - (expireEventsSeconds * 1000)) } }, { multi: true }); // Force delete older events obj.powerfile.remove({ time: { '$lt': new Date(Date.now() - (expirePowerEventsSeconds * 1000)) } }, { multi: true }); // Force delete older events obj.serverstatsfile.remove({ time: { '$lt': new Date(Date.now() - (expireServerStatsSeconds * 1000)) } }, { multi: true }); // Force delete older events - } else if ((obj.databaseType == 4) || (obj.databaseType == 5)) { // MariaDB or MySQL + } else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) { // MariaDB or MySQL sqlDbQuery('DELETE FROM events WHERE time < ?', [new Date(Date.now() - (expireEventsSeconds * 1000))], function (doc, err) { }); // Delete events older than expireEventsSeconds sqlDbQuery('DELETE FROM power WHERE time < ?', [new Date(Date.now() - (expirePowerEventsSeconds * 1000))], function (doc, err) { }); // Delete events older than expirePowerSeconds sqlDbQuery('DELETE FROM serverstats WHERE expire < ?', [new Date()], function (doc, err) { }); // Delete events where expiration date is in the past sqlDbQuery('DELETE FROM smbios WHERE expire < ?', [new Date()], function (doc, err) { }); // Delete events where expiration date is in the past - } else if (obj.databaseType == 7) { // AceBase + } else if (obj.databaseType == DB_ACEBASE) { // AceBase //console.log('Performing AceBase maintenance'); obj.file.query('events').filter('time', '<', new Date(Date.now() - (expireEventsSeconds * 1000))).remove().then(function () { obj.file.query('stats').filter('time', '<', new Date(Date.now() - (expireServerStatsSeconds * 1000))).remove().then(function () { @@ -123,8 +149,22 @@ module.exports.CreateDB = function (parent, func) { }); }); }); - } else if (obj.databaseType == 8) { // SQLite3 - // TODO + } else if (obj.databaseType == DB_SQLITE) { // SQLite3 + //sqlite does not return rows affected for INSERT, UPDATE or DELETE statements, see https://www.sqlite.org/pragma.html#pragma_count_changes + obj.file.serialize(function () { + obj.file.run('DELETE FROM events WHERE time < ?', [new Date(Date.now() - (expireEventsSeconds * 1000))]); + obj.file.run('DELETE FROM power WHERE time < ?', [new Date(Date.now() - (expirePowerEventsSeconds * 1000))]); + obj.file.run('DELETE FROM serverstats WHERE expire < ?', [new Date()]); + obj.file.run('DELETE FROM smbios WHERE expire < ?', [new Date()]); + obj.file.exec(obj.sqliteConfig.maintenance, function (err) { + if (err) {console.log('Maintenance error: ' + err.message)}; + if (parent.config.settings.debug) { + sqliteGetPragmas(['freelist_count', 'page_size', 'page_count', 'cache_size' ], function (pragma, pragmaValue) { + parent.debug('db', 'SQLite Maintenance: ' + pragma + '=' + pragmaValue); + }); + }; + }); + }); } obj.removeInactiveDevices(); } @@ -136,7 +176,7 @@ module.exports.CreateDB = function (parent, func) { for (var i in parent.config.domains) { if (typeof parent.config.domains[i].autoremoveinactivedevices == 'number') { var v = parent.config.domains[i].autoremoveinactivedevices; - if ((v > 1) && (v <= 2000)) { + if ((v >= 1) && (v <= 2000)) { if (v < minRemoveInactiveDevice) { minRemoveInactiveDevice = v; } removeInactiveDevicesPerDomain[i] = v; minRemoveInactiveDevicesPerDomain[i] = v; @@ -148,7 +188,7 @@ module.exports.CreateDB = function (parent, func) { for (var i in parent.webserver.meshes) { if (typeof parent.webserver.meshes[i].expireDevs == 'number') { var v = parent.webserver.meshes[i].expireDevs; - if ((v > 1) && (v <= 2000)) { + if ((v >= 1) && (v <= 2000)) { if (v < minRemoveInactiveDevice) { minRemoveInactiveDevice = v; } if ((minRemoveInactiveDevicesPerDomain[parent.webserver.meshes[i].domain] == null) || (minRemoveInactiveDevicesPerDomain[parent.webserver.meshes[i].domain] > v)) { minRemoveInactiveDevicesPerDomain[parent.webserver.meshes[i].domain] = v; @@ -245,18 +285,18 @@ module.exports.CreateDB = function (parent, func) { obj.removeDomain = function (domainName, func) { var pendingCalls; // Remove all events, power events and SMBIOS data from the main collection. They are all in seperate collections now. - if (obj.databaseType == 7) { + if (obj.databaseType == DB_ACEBASE) { // AceBase pendingCalls = 3; obj.file.query('meshcentral').filter('domain', '==', domainName).remove().then(function () { if (--pendingCalls == 0) { func(); } }); obj.file.query('events').filter('domain', '==', domainName).remove().then(function () { if (--pendingCalls == 0) { func(); } }); obj.file.query('power').filter('domain', '==', domainName).remove().then(function () { if (--pendingCalls == 0) { func(); } }); - } else if ((obj.databaseType == 4) || (obj.databaseType == 5) || (obj.databaseType == 6)) { + } else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL) || (obj.databaseType == DB_POSTGRESQL)) { // MariaDB, MySQL or PostgreSQL pendingCalls = 2; sqlDbQuery('DELETE FROM main WHERE domain = $1', [domainName], function () { if (--pendingCalls == 0) { func(); } }); sqlDbQuery('DELETE FROM events WHERE domain = $1', [domainName], function () { if (--pendingCalls == 0) { func(); } }); - } else if (obj.databaseType == 3) { + } else if (obj.databaseType == DB_MONGODB) { // MongoDB pendingCalls = 3; obj.file.deleteMany({ domain: domainName }, { multi: true }, function () { if (--pendingCalls == 0) { func(); } }); @@ -276,17 +316,17 @@ module.exports.CreateDB = function (parent, func) { // TODO: Remove all meshes that dont have any links // Remove all events, power events and SMBIOS data from the main collection. They are all in seperate collections now. - if ((obj.databaseType == 4) || (obj.databaseType == 5) || (obj.databaseType == 6)) { + if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL) || (obj.databaseType == DB_POSTGRESQL)) { // MariaDB, MySQL or PostgreSQL obj.RemoveAllOfType('event', function () { }); obj.RemoveAllOfType('power', function () { }); obj.RemoveAllOfType('smbios', function () { }); - } else if (obj.databaseType == 3) { + } else if (obj.databaseType == DB_MONGODB) { // MongoDB obj.file.deleteMany({ type: 'event' }, { multi: true }); obj.file.deleteMany({ type: 'power' }, { multi: true }); obj.file.deleteMany({ type: 'smbios' }, { multi: true }); - } else if ((obj.databaseType == 1) || (obj.databaseType == 2)) { + } else if ((obj.databaseType == DB_NEDB) || (obj.databaseType == DB_MONGOJS)) { // NeDB or MongoJS obj.file.remove({ type: 'event' }, { multi: true }); obj.file.remove({ type: 'power' }, { multi: true }); @@ -387,19 +427,19 @@ module.exports.CreateDB = function (parent, func) { if (meshChange) { obj.Set(docs[i]); } } } - if (obj.databaseType == 8) { + if (obj.databaseType == DB_SQLITE) { // SQLite - } else if (obj.databaseType == 7) { + } else if (obj.databaseType == DB_ACEBASE) { // AceBase - } else if (obj.databaseType == 6) { + } else if (obj.databaseType == DB_POSTGRESQL) { // Postgres sqlDbQuery('DELETE FROM Main WHERE ((extra != NULL) AND (extra LIKE (\'mesh/%\')) AND (extra != ANY ($1)))', [meshlist], function (err, response) { }); - } else if ((obj.databaseType == 4) || (obj.databaseType == 5)) { + } else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) { // MariaDB sqlDbQuery('DELETE FROM Main WHERE (extra LIKE ("mesh/%") AND (extra NOT IN ?)', [meshlist], function (err, response) { }); - } else if (obj.databaseType == 3) { + } else if (obj.databaseType == DB_MONGODB) { // MongoDB obj.file.deleteMany({ meshid: { $exists: true, $nin: meshlist } }, { multi: true }); } else { @@ -417,14 +457,66 @@ module.exports.CreateDB = function (parent, func) { }; // Get encryption key - obj.getEncryptDataKey = function (password) { + obj.getEncryptDataKey = function (password, salt, iterations) { if (typeof password != 'string') return null; - return parent.crypto.createHash('sha384').update(password).digest("raw").slice(0, 32); + let key; + try { + key = parent.crypto.pbkdf2Sync(password, salt, iterations, 32, 'sha384'); + } catch (ex) { + // If this previous call fails, it's probably because older pbkdf2 did not specify the hashing function, just use the default. + key = parent.crypto.pbkdf2Sync(password, salt, iterations, 32); + } + return key } // Encrypt data obj.encryptData = function (password, plaintext) { - var key = obj.getEncryptDataKey(password); + let encryptionVersion = 0x01; + let iterations = 100000 + const iv = parent.crypto.randomBytes(16); + var key = obj.getEncryptDataKey(password, iv, iterations); + if (key == null) return null; + const aes = parent.crypto.createCipheriv('aes-256-gcm', key, iv); + var ciphertext = aes.update(plaintext); + let versionbuf = Buffer.allocUnsafe(2); + versionbuf.writeUInt16BE(encryptionVersion); + let iterbuf = Buffer.allocUnsafe(4); + iterbuf.writeUInt32BE(iterations); + let encryptedBuf = aes.final(); + ciphertext = Buffer.concat([versionbuf, iterbuf, aes.getAuthTag(), iv, ciphertext, encryptedBuf]); + return ciphertext.toString('base64'); + } + + // Decrypt data + obj.decryptData = function (password, ciphertext) { + // Adding an encryption version lets us avoid try catching in the future + let ciphertextBytes = Buffer.from(ciphertext, 'base64'); + let encryptionVersion = ciphertextBytes.readUInt16BE(0); + try { + switch (encryptionVersion) { + case 0x01: + let iterations = ciphertextBytes.readUInt32BE(2); + let authTag = ciphertextBytes.slice(6, 22); + const iv = ciphertextBytes.slice(22, 38); + const data = ciphertextBytes.slice(38); + let key = obj.getEncryptDataKey(password, iv, iterations); + if (key == null) return null; + const aes = parent.crypto.createDecipheriv('aes-256-gcm', key, iv); + aes.setAuthTag(authTag); + let plaintextBytes = Buffer.from(aes.update(data)); + plaintextBytes = Buffer.concat([plaintextBytes, aes.final()]); + return plaintextBytes; + default: + return obj.oldDecryptData(password, ciphertextBytes); + } + } catch (ex) { return obj.oldDecryptData(password, ciphertextBytes); } + } + + // Encrypt data + // The older encryption system uses CBC without integraty checking. + // This method is kept only for testing + obj.oldEncryptData = function (password, plaintext) { + let key = parent.crypto.createHash('sha384').update(password).digest('raw').slice(0, 32); if (key == null) return null; const iv = parent.crypto.randomBytes(16); const aes = parent.crypto.createCipheriv('aes-256-cbc', key, iv); @@ -433,16 +525,17 @@ module.exports.CreateDB = function (parent, func) { return ciphertext.toString('base64'); } - // Decrypt data - obj.decryptData = function (password, ciphertext) { + // Decrypt data + // The older encryption system uses CBC without integraty checking. + // This method is kept only to convert the old encryption to the new one. + obj.oldDecryptData = function (password, ciphertextBytes) { + if (typeof password != 'string') return null; try { - var key = obj.getEncryptDataKey(password); - if (key == null) return null; - const ciphertextBytes = Buffer.from(ciphertext, 'base64'); const iv = ciphertextBytes.slice(0, 16); const data = ciphertextBytes.slice(16); + let key = parent.crypto.createHash('sha384').update(password).digest('raw').slice(0, 32); const aes = parent.crypto.createDecipheriv('aes-256-cbc', key, iv); - var plaintextBytes = Buffer.from(aes.update(data)); + let plaintextBytes = Buffer.from(aes.update(data)); plaintextBytes = Buffer.concat([plaintextBytes, aes.final()]); return plaintextBytes; } catch (ex) { return null; } @@ -451,33 +544,33 @@ module.exports.CreateDB = function (parent, func) { // Get the number of records in the database for various types, this is the slow NeDB way. // WARNING: This is a terrible query for database performance. Only do this when needed. This query will look at almost every document in the database. obj.getStats = function (func) { - if (obj.databaseType == 7) { + if (obj.databaseType == DB_ACEBASE) { // AceBase // TODO - } else if (obj.databaseType == 6) { + } else if (obj.databaseType == DB_POSTGRESQL) { // PostgreSQL // TODO - } else if (obj.databaseType == 5) { + } else if (obj.databaseType == DB_MYSQL) { // MySQL // TODO - } else if (obj.databaseType == 4) { + } else if (obj.databaseType == DB_MARIADB) { // MariaDB // TODO - } else if (obj.databaseType == 3) { + } else if (obj.databaseType == DB_MONGODB) { // MongoDB obj.file.aggregate([{ "$group": { _id: "$type", count: { $sum: 1 } } }]).toArray(function (err, docs) { var counters = {}, totalCount = 0; if (err == null) { for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } } } func(counters); }); - } else if (obj.databaseType == 2) { + } else if (obj.databaseType == DB_MONGOJS) { // MongoJS obj.file.aggregate([{ "$group": { _id: "$type", count: { $sum: 1 } } }], function (err, docs) { var counters = {}, totalCount = 0; if (err == null) { for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } } } func(counters); }); - } else if (obj.databaseType == 1) { + } else if (obj.databaseType == DB_NEDB) { // NeDB version obj.file.count({ type: 'node' }, function (err, nodeCount) { obj.file.count({ type: 'mesh' }, function (err, meshCount) { @@ -517,8 +610,8 @@ module.exports.CreateDB = function (parent, func) { if (err == null) { for (var i in docs) { count++; obj.Set(docs[i]); } } obj.GetAllType('mesh', function (err, docs) { if (err == null) { for (var i in docs) { count++; obj.Set(docs[i]); } } - if (obj.databaseType == 1) { // If we are using NeDB, compact the database. - obj.file.persistence.compactDatafile(); + if (obj.databaseType == DB_NEDB) { // If we are using NeDB, compact the database. + obj.file.compactDatafile(); obj.file.on('compaction.done', function () { func(count); }); // It's important to wait for compaction to finish before exit, otherwise NeDB may corrupt. } else { func(count); // For all other databases, normal exit. @@ -668,13 +761,31 @@ module.exports.CreateDB = function (parent, func) { if (parent.args.sqlite3) { // SQLite3 database setup - obj.databaseType = 8; + obj.databaseType = DB_SQLITE; const sqlite3 = require('sqlite3'); - obj.file = new sqlite3.Database(parent.path.join(parent.datapath, 'meshcentral.sqlite'), sqlite3.OPEN_READWRITE, function (err) { + let configParams = parent.config.settings.sqlite3; + if (typeof configParams == 'string') {databaseName = configParams} else {databaseName = configParams.name ? configParams.name : 'meshcentral';}; + obj.sqliteConfig.startupVacuum = configParams.startupvacuum ? configParams.startupvacuum : false; + obj.sqliteConfig.autoVacuum = configParams.autovacuum ? configParams.autovacuum.toLowerCase() : 'incremental'; + obj.sqliteConfig.incrementalVacuum = configParams.incrementalvacuum ? configParams.incrementalvacuum : 100; + obj.sqliteConfig.journalMode = configParams.journalmode ? configParams.journalmode.toLowerCase() : 'delete'; + //allowed modes, 'none' excluded because not usefull for this app, maybe also remove 'memory'? + if (!(['delete', 'truncate', 'persist', 'memory', 'wal'].includes(obj.sqliteConfig.journalMode))) { obj.sqliteConfig.journalMode = 'delete'}; + obj.sqliteConfig.journalSize = configParams.journalsize ? configParams.journalsize : 409600; + //wal can use the more performant 'normal' mode, see https://www.sqlite.org/pragma.html#pragma_synchronous + obj.sqliteConfig.synchronous = (obj.sqliteConfig.journalMode == 'wal') ? 'normal' : 'full'; + if (obj.sqliteConfig.journalMode == 'wal') {obj.sqliteConfig.maintenance += 'PRAGMA wal_checkpoint(PASSIVE);'}; + if (obj.sqliteConfig.autoVacuum == 'incremental') {obj.sqliteConfig.maintenance += 'PRAGMA incremental_vacuum(' + obj.sqliteConfig.incrementalVacuum + ');'}; + obj.sqliteConfig.maintenance += 'PRAGMA optimize;'; + + parent.debug('db', 'SQlite config options: ' + JSON.stringify(obj.sqliteConfig, null, 4)); + if (obj.sqliteConfig.journalMode == 'memory') { console.log('[WARNING] journal_mode=memory: this can lead to database corruption if there is a crash during a transaction. See https://www.sqlite.org/pragma.html#pragma_journal_mode') }; + //.cached not usefull + obj.file = new sqlite3.Database(path.join(parent.datapath, databaseName + '.sqlite'), sqlite3.OPEN_READWRITE, function (err) { if (err && (err.code == 'SQLITE_CANTOPEN')) { // Database needs to be created - obj.file = new sqlite3.Database(parent.path.join(parent.datapath, 'meshcentral.sqlite'), function (err) { - if (err) { console.log("SQLite Error: " + err); exit(1); return; } + obj.file = new sqlite3.Database(path.join(parent.datapath, databaseName + '.sqlite'), function (err) { + if (err) { console.log("SQLite Error: " + err); process.exit(1); } obj.file.exec(` CREATE TABLE main (id VARCHAR(256) PRIMARY KEY NOT NULL, type CHAR(32), domain CHAR(64), extra CHAR(255), extraex CHAR(255), doc JSON); CREATE TABLE events(id INTEGER PRIMARY KEY, time TIMESTAMP, domain CHAR(64), action CHAR(255), nodeid CHAR(255), userid CHAR(255), doc JSON); @@ -696,20 +807,24 @@ module.exports.CreateDB = function (parent, func) { CREATE INDEX ndxsmbiostime ON smbios (time); CREATE INDEX ndxsmbiosexpire ON smbios (expire); `, function (err) { - // Completed setup of SQLite3 + // Completed DB creation of SQLite3 + sqliteSetOptions(func); + //setupFunctions could be put in the sqliteSetupOptions, but left after it for clarity setupFunctions(func); } ); }); return; - } else if (err) { console.log("SQLite Error: " + err); exit(1); return; } + } else if (err) { console.log("SQLite Error: " + err); process.exit(0); } - // Completed setup of SQLite3 + //for existing db's + sqliteSetOptions(); + //setupFunctions could be put in the sqliteSetupOptions, but left after it for clarity setupFunctions(func); }); } else if (parent.args.acebase) { // AceBase database setup - obj.databaseType = 7; + obj.databaseType = DB_ACEBASE; const { AceBase } = require('acebase'); // For information on AceBase sponsor: https://github.com/appy-one/acebase/discussions/100 obj.file = new AceBase('meshcentral', { sponsor: ((typeof parent.args.acebase == 'object') && (parent.args.acebase.sponsor)), logLevel: 'error', storage: { path: parent.datapath } }); @@ -733,27 +848,39 @@ module.exports.CreateDB = function (parent, func) { }); } else if (parent.args.mariadb || parent.args.mysql) { var connectinArgs = (parent.args.mariadb) ? parent.args.mariadb : parent.args.mysql; - var dbname = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral'; + if (typeof connectinArgs == 'string') { + const parts = connectinArgs.split(/[:@/]+/); + var connectionObject = { + "user": parts[1], + "password": parts[2], + "host": parts[3], + "port": parts[4], + "database": parts[5] + }; + var dbname = (connectionObject.database != null) ? connectionObject.database : 'meshcentral'; + } else { + var dbname = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral'; - // Including the db name in the connection obj will cause a connection faliure if it does not exist - var connectionObject = Clone(connectinArgs); - delete connectionObject.database; + // Including the db name in the connection obj will cause a connection faliure if it does not exist + var connectionObject = Clone(connectinArgs); + delete connectionObject.database; - try { - if (connectinArgs.ssl) { - if (connectinArgs.ssl.dontcheckserveridentity == true) { connectionObject.ssl.checkServerIdentity = function (name, cert) { return undefined; } }; - if (connectinArgs.ssl.cacertpath) { connectionObject.ssl.ca = [require('fs').readFileSync(connectinArgs.ssl.cacertpath, 'utf8')]; } - if (connectinArgs.ssl.clientcertpath) { connectionObject.ssl.cert = [require('fs').readFileSync(connectinArgs.ssl.clientcertpath, 'utf8')]; } - if (connectinArgs.ssl.clientkeypath) { connectionObject.ssl.key = [require('fs').readFileSync(connectinArgs.ssl.clientkeypath, 'utf8')]; } + try { + if (connectinArgs.ssl) { + if (connectinArgs.ssl.dontcheckserveridentity == true) { connectionObject.ssl.checkServerIdentity = function (name, cert) { return undefined; } }; + if (connectinArgs.ssl.cacertpath) { connectionObject.ssl.ca = [require('fs').readFileSync(connectinArgs.ssl.cacertpath, 'utf8')]; } + if (connectinArgs.ssl.clientcertpath) { connectionObject.ssl.cert = [require('fs').readFileSync(connectinArgs.ssl.clientcertpath, 'utf8')]; } + if (connectinArgs.ssl.clientkeypath) { connectionObject.ssl.key = [require('fs').readFileSync(connectinArgs.ssl.clientkeypath, 'utf8')]; } + } + } catch (ex) { + console.log('Error loading SQL Connector certificate: ' + ex); + process.exit(); } - } catch (ex) { - console.log('Error loading SQL Connector certificate: ' + ex); - process.exit(); } if (parent.args.mariadb) { // Use MariaDB - obj.databaseType = 4; + obj.databaseType = DB_MARIADB; var tempDatastore = require('mariadb').createPool(connectionObject); tempDatastore.getConnection().then(function (conn) { conn.query('CREATE DATABASE IF NOT EXISTS ' + dbname).then(function (result) { @@ -767,49 +894,70 @@ module.exports.CreateDB = function (parent, func) { createTablesIfNotExist(dbname); } else if (parent.args.mysql) { // Use MySQL - obj.databaseType = 5; - var tempDatastore = require('mysql').createPool(connectionObject); + obj.databaseType = DB_MYSQL; + var tempDatastore = require('mysql2').createPool(connectionObject); tempDatastore.query('CREATE DATABASE IF NOT EXISTS ' + dbname, function (error) { if (error != null) { console.log('Auto-create database failed: ' + error); } connectionObject.database = dbname; - Datastore = require('mysql').createPool(connectionObject); + Datastore = require('mysql2').createPool(connectionObject); createTablesIfNotExist(dbname); }); setTimeout(function () { tempDatastore.end(); }, 2000); } } else if (parent.args.postgres) { // Postgres SQL - var connectinArgs = parent.args.postgres; - var dbname = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral'; - delete connectinArgs.database; - obj.databaseType = 6; - const pgtools = require('pgtools'); - pgtools.createdb(connectinArgs, dbname, function (err, res) { - const { Pool, Client } = require('pg'); - connectinArgs.database = dbname; - Datastore = new Client(connectinArgs); - Datastore.connect(); - if (err == null) { - // Create the tables and indexes - postgreSqlCreateTables(func); - } else { - // Database already existed, perform a test query to see if the main table is present - sqlDbQuery('SELECT doc FROM main WHERE id = $1', ['DatabaseIdentifier'], function (err, docs) { - if (err == null) { setupFunctions(func); } else { postgreSqlCreateTables(func); } // If not present, create the tables and indexes + let connectinArgs = parent.args.postgres; + connectinArgs.database = (databaseName = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral'); + + let DatastoreTest; + obj.databaseType = DB_POSTGRESQL; + const { Client } = require('pg'); + Datastore = new Client(connectinArgs); + //Connect to and check pg db first to check if own db exists. Otherwise errors out on 'database does not exist' + connectinArgs.database = 'postgres'; + DatastoreTest = new Client(connectinArgs); + DatastoreTest.connect(); + + DatastoreTest.query('SELECT 1 FROM pg_catalog.pg_database WHERE datname = $1', [databaseName], function (err, res) { // check database exists first before creating + if (res.rowCount != 0) { // database exists now check tables exists + DatastoreTest.end(); + Datastore.connect(); + Datastore.query('SELECT doc FROM main WHERE id = $1', ['DatabaseIdentifier'], function (err, res) { + if (err == null) { + (res.rowCount ==0) ? postgreSqlCreateTables(func) : setupFunctions(func) + } else + if (err.code == '42P01') { //42P01 = undefined table, https://www.postgresql.org/docs/current/errcodes-appendix.html + postgreSqlCreateTables(func); + } else { + console.log('Postgresql database exists, other error: ', err.message); process.exit(0); + }; + }); + } else { // If not present, create the tables and indexes + //not needed, just use a create db statement: const pgtools = require('pgtools'); + DatastoreTest.query('CREATE DATABASE '+ databaseName + ';', [], function (err, res) { + if (err == null) { + // Create the tables and indexes + DatastoreTest.end(); + Datastore.connect(); + postgreSqlCreateTables(func); + } else { + console.log('Postgresql database create error: ', err.message); + process.exit(0); + } }); } }); } else if (parent.args.mongodb) { // Use MongoDB - obj.databaseType = 3; + obj.databaseType = DB_MONGODB; // If running an older NodeJS version, TextEncoder/TextDecoder is required if (global.TextEncoder == null) { global.TextEncoder = require('util').TextEncoder; } if (global.TextDecoder == null) { global.TextDecoder = require('util').TextDecoder; } - require('mongodb').MongoClient.connect(parent.args.mongodb, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) { + require('mongodb').MongoClient.connect(parent.args.mongodb, { useNewUrlParser: true, useUnifiedTopology: true, enableUtf8Validation: false }, function (err, client) { if (err != null) { console.log("Unable to connect to database: " + err); process.exit(); return; } Datastore = client; parent.debug('db', 'Connected to MongoDB database...'); @@ -827,7 +975,7 @@ module.exports.CreateDB = function (parent, func) { } else { if ((info.versionArray[0] < 3) || ((info.versionArray[0] == 3) && (info.versionArray[1] < 6))) { // We are running with mongoDB older than 3.6, this is not good. - parent.addServerWarning("Current version of MongoDB (" + info.version + ") is too old, please upgrade to MongoDB 3.6 or better."); + parent.addServerWarning("Current version of MongoDB (" + info.version + ") is too old, please upgrade to MongoDB 3.6 or better.", true); } } }); @@ -986,7 +1134,7 @@ module.exports.CreateDB = function (parent, func) { }); } else if (parent.args.xmongodb) { // Use MongoJS, this is the old system. - obj.databaseType = 2; + obj.databaseType = DB_MONGOJS; Datastore = require('mongojs'); var db = Datastore(parent.args.xmongodb); var dbcollection = 'meshcentral'; @@ -1090,9 +1238,12 @@ module.exports.CreateDB = function (parent, func) { setupFunctions(func); // Completed setup of MongoJS } else { // Use NeDB (The default) - obj.databaseType = 1; - try { Datastore = require('@yetzt/nedb'); } catch (ex) { } // This is the NeDB with fixed security dependencies. - if (Datastore == null) { Datastore = require('nedb'); } // So not to break any existing installations, if the old NeDB is present, use it. + obj.databaseType = DB_NEDB; + try { Datastore = require('@seald-io/nedb'); } catch (ex) { } // This is the NeDB with Node 23 support. + if (Datastore == null) { + try { Datastore = require('@yetzt/nedb'); } catch (ex) { } // This is the NeDB with fixed security dependencies. + if (Datastore == null) { Datastore = require('nedb'); } // So not to break any existing installations, if the old NeDB is present, use it. + } var datastoreOptions = { filename: parent.getConfigFilePath('meshcentral.db'), autoload: true }; // If a DB encryption key is provided, perform database encryption @@ -1119,7 +1270,7 @@ module.exports.CreateDB = function (parent, func) { // Start NeDB main collection and setup indexes obj.file = new Datastore(datastoreOptions); - obj.file.persistence.setAutocompactionInterval(86400000); // Compact once a day + obj.file.setAutocompactionInterval(86400000); // Compact once a day obj.file.ensureIndex({ fieldName: 'type' }); obj.file.ensureIndex({ fieldName: 'domain' }); obj.file.ensureIndex({ fieldName: 'meshid', sparse: true }); @@ -1128,7 +1279,7 @@ module.exports.CreateDB = function (parent, func) { // Setup the events collection and setup indexes obj.eventsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-events.db'), autoload: true, corruptAlertThreshold: 1 }); - obj.eventsfile.persistence.setAutocompactionInterval(86400000); // Compact once a day + obj.eventsfile.setAutocompactionInterval(86400000); // Compact once a day obj.eventsfile.ensureIndex({ fieldName: 'ids' }); // TODO: Not sure if this is a good index, this is a array field. obj.eventsfile.ensureIndex({ fieldName: 'nodeid', sparse: true }); obj.eventsfile.ensureIndex({ fieldName: 'time', expireAfterSeconds: expireEventsSeconds }); @@ -1136,18 +1287,18 @@ module.exports.CreateDB = function (parent, func) { // Setup the power collection and setup indexes obj.powerfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-power.db'), autoload: true, corruptAlertThreshold: 1 }); - obj.powerfile.persistence.setAutocompactionInterval(86400000); // Compact once a day + obj.powerfile.setAutocompactionInterval(86400000); // Compact once a day obj.powerfile.ensureIndex({ fieldName: 'nodeid' }); obj.powerfile.ensureIndex({ fieldName: 'time', expireAfterSeconds: expirePowerEventsSeconds }); obj.powerfile.remove({ time: { '$lt': new Date(Date.now() - (expirePowerEventsSeconds * 1000)) } }, { multi: true }); // Force delete older events // Setup the SMBIOS collection, for NeDB we don't setup SMBIOS since NeDB will corrupt the database. Remove any existing ones. //obj.smbiosfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-smbios.db'), autoload: true, corruptAlertThreshold: 1 }); - parent.fs.unlink(parent.getConfigFilePath('meshcentral-smbios.db'), function () { }); + fs.unlink(parent.getConfigFilePath('meshcentral-smbios.db'), function () { }); // Setup the server stats collection and setup indexes obj.serverstatsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-stats.db'), autoload: true, corruptAlertThreshold: 1 }); - obj.serverstatsfile.persistence.setAutocompactionInterval(86400000); // Compact once a day + obj.serverstatsfile.setAutocompactionInterval(86400000); // Compact once a day obj.serverstatsfile.ensureIndex({ fieldName: 'time', expireAfterSeconds: expireServerStatsSeconds }); obj.serverstatsfile.ensureIndex({ fieldName: 'expire', expireAfterSeconds: 0 }); // Auto-expire events obj.serverstatsfile.remove({ time: { '$lt': new Date(Date.now() - (expireServerStatsSeconds * 1000)) } }, { multi: true }); // Force delete older events @@ -1155,12 +1306,51 @@ module.exports.CreateDB = function (parent, func) { // Setup plugin info collection if (obj.pluginsActive) { obj.pluginsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-plugins.db'), autoload: true }); - obj.pluginsfile.persistence.setAutocompactionInterval(86400000); // Compact once a day + obj.pluginsfile.setAutocompactionInterval(86400000); // Compact once a day } setupFunctions(func); // Completed setup of NeDB } + function sqliteSetOptions(func) { + //get current auto_vacuum mode for comparison + obj.file.get('PRAGMA auto_vacuum;', function(err, current){ + let pragma = 'PRAGMA journal_mode=' + obj.sqliteConfig.journalMode + ';' + + 'PRAGMA synchronous='+ obj.sqliteConfig.synchronous + ';' + + 'PRAGMA journal_size_limit=' + obj.sqliteConfig.journalSize + ';' + + 'PRAGMA auto_vacuum=' + obj.sqliteConfig.autoVacuum + ';' + + 'PRAGMA incremental_vacuum=' + obj.sqliteConfig.incrementalVacuum + ';' + + 'PRAGMA optimize=0x10002;'; + //check new autovacuum mode, if changing from or to 'none', a VACUUM needs to be done to activate it. See https://www.sqlite.org/pragma.html#pragma_auto_vacuum + if ( obj.sqliteConfig.startupVacuum + || (current.auto_vacuum == 0 && obj.sqliteConfig.autoVacuum !='none') + || (current.auto_vacuum != 0 && obj.sqliteConfig.autoVacuum =='none')) + { + pragma += 'VACUUM;'; + }; + parent.debug ('db', 'Config statement: ' + pragma); + + obj.file.exec( pragma, + function (err) { + if (err) { parent.debug('db', 'Config pragma error: ' + (err.message)) }; + sqliteGetPragmas(['journal_mode', 'journal_size_limit', 'freelist_count', 'auto_vacuum', 'page_size', 'wal_autocheckpoint', 'synchronous'], function (pragma, pragmaValue) { + parent.debug('db', 'PRAGMA: ' + pragma + '=' + pragmaValue); + }); + }); + }); + //setupFunctions(func); + } + + function sqliteGetPragmas (pragmas, func){ + //pragmas can only be gotting one by one + pragmas.forEach (function (pragma) { + obj.file.get('PRAGMA ' + pragma + ';', function(err, res){ + if (pragma == 'auto_vacuum') { res[pragma] = SQLITE_AUTOVACUUM[res[pragma]] }; + if (pragma == 'synchronous') { res[pragma] = SQLITE_SYNCHRONOUS[res[pragma]] }; + if (func) { func (pragma, res[pragma]); } + }); + }); + } // Create the PostgreSQL tables function postgreSqlCreateTables(func) { // Database was created, create the tables @@ -1202,7 +1392,7 @@ module.exports.CreateDB = function (parent, func) { // Query the database function sqlDbQuery(query, args, func, debug) { - if (obj.databaseType == 8) { // SQLite + if (obj.databaseType == DB_SQLITE) { // SQLite if (args == null) { args = []; } obj.file.all(query, args, function (err, docs) { if (err != null) { console.log(query, args, err, docs); } @@ -1217,7 +1407,7 @@ module.exports.CreateDB = function (parent, func) { } if (func) { func(err, docs); } }); - } else if (obj.databaseType == 4) { // MariaDB + } else if (obj.databaseType == DB_MARIADB) { // MariaDB Datastore.getConnection() .then(function (conn) { conn.query(query, args) @@ -1236,7 +1426,7 @@ module.exports.CreateDB = function (parent, func) { }) .catch(function (err) { conn.release(); if (func) try { func(err); } catch (ex) { console.log('SQLERR2', ex); } }); }).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log('SQLERR3', ex); } } }); - } else if (obj.databaseType == 5) { // MySQL + } else if (obj.databaseType == DB_MYSQL) { // MySQL Datastore.query(query, args, function (error, results, fields) { if (error != null) { if (func) try { func(error); } catch (ex) { console.log('SQLERR4', ex); } @@ -1244,7 +1434,11 @@ module.exports.CreateDB = function (parent, func) { var docs = []; for (var i in results) { if (results[i].doc) { - docs.push(JSON.parse(results[i].doc)); + if (typeof results[i].doc == 'string') { + docs.push(JSON.parse(results[i].doc)); + } else { + docs.push(results[i].doc); + } } else if ((results.length == 1) && (results[i]['COUNT(doc)'] != null)) { // This is a SELECT COUNT() operation docs = results[i]['COUNT(doc)']; @@ -1253,10 +1447,9 @@ module.exports.CreateDB = function (parent, func) { if (func) { try { func(null, docs); } catch (ex) { console.log('SQLERR5', ex); } } } }); - } else if (obj.databaseType == 6) { // Postgres SQL + } else if (obj.databaseType == DB_POSTGRESQL) { // Postgres SQL Datastore.query(query, args, function (error, results) { if (error != null) { - console.log(query, args, error); if (func) try { func(error); } catch (ex) { console.log('SQLERR4', ex); } } else { var docs = []; @@ -1283,7 +1476,7 @@ module.exports.CreateDB = function (parent, func) { // Exec on the database function sqlDbExec(query, args, func) { - if (obj.databaseType == 4) { // MariaDB + if (obj.databaseType == DB_MARIADB) { // MariaDB Datastore.getConnection() .then(function (conn) { conn.query(query, args) @@ -1293,7 +1486,7 @@ module.exports.CreateDB = function (parent, func) { }) .catch(function (err) { conn.release(); if (func) try { func(err); } catch (ex) { console.log(ex); } }); }).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } }); - } else if ((obj.databaseType == 5) || (obj.databaseType == 6)) { // MySQL or Postgres SQL + } else if ((obj.databaseType == DB_MYSQL) || (obj.databaseType == DB_POSTGRESQL)) { // MySQL or Postgres SQL Datastore.query(query, args, function (error, results, fields) { if (func) try { func(error, results ? results[0] : null); } catch (ex) { console.log(ex); } }); @@ -1302,7 +1495,7 @@ module.exports.CreateDB = function (parent, func) { // Execute a batch of commands on the database function sqlDbBatchExec(queries, func) { - if (obj.databaseType == 4) { // MariaDB + if (obj.databaseType == DB_MARIADB) { // MariaDB Datastore.getConnection() .then(function (conn) { var Promises = []; @@ -1312,7 +1505,16 @@ module.exports.CreateDB = function (parent, func) { .catch(function (err) { conn.release(); if (func) { try { func(err); } catch (ex) { console.log(ex); } } }); }) .catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } }); - } else if ((obj.databaseType == 5) || (obj.databaseType == 6)) { // MySQL + } else if (obj.databaseType == DB_MYSQL) { // MySQL + Datastore.getConnection(function(err, connection) { + if (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } return; } + var Promises = []; + for (var i in queries) { if (typeof queries[i] == 'string') { Promises.push(connection.promise().query(queries[i])); } else { Promises.push(connection.promise().query(queries[i][0], queries[i][1])); } } + Promise.all(Promises) + .then(function (error, results, fields) { connection.release(); if (func) { try { func(error, results); } catch (ex) { console.log(ex); } } }) + .catch(function (error, results, fields) { connection.release(); if (func) { try { func(error); } catch (ex) { console.log(ex); } } }); + }); + } else if (obj.databaseType == DB_POSTGRESQL) { // Postgres var Promises = []; for (var i in queries) { if (typeof queries[i] == 'string') { Promises.push(Datastore.query(queries[i])); } else { Promises.push(Datastore.query(queries[i][0], queries[i][1])); } } Promise.all(Promises) @@ -1322,7 +1524,7 @@ module.exports.CreateDB = function (parent, func) { } function setupFunctions(func) { - if (obj.databaseType == 8) { + if (obj.databaseType == DB_SQLITE) { // Database actions on the main collection. SQLite3: https://www.linode.com/docs/guides/getting-started-with-nodejs-sqlite/ obj.Set = function (value, func) { obj.dbCounters.fileSet++; @@ -1447,12 +1649,12 @@ module.exports.CreateDB = function (parent, func) { obj.RemoveMeshDocuments = function (id, func) { sqlDbQuery('DELETE FROM main WHERE extra = $1', [id], function () { sqlDbQuery('DELETE FROM main WHERE id = $1', ['nt' + id], func); }); }; obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; obj.DeleteDomain = function (domain, func) { sqlDbQuery('DELETE FROM main WHERE domain = $1', [domain], func); }; - obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; + obj.SetUser = function (user) { if (user == null) return; if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; obj.getLocalAmtNodes = function (func) { - sqlDbQuery('SELECT doc FROM main WHERE (type = \'node\') AND (extraex IS NOT NULL)', null, function (err, docs) { + sqlDbQuery('SELECT doc FROM main WHERE (type = \'node\') AND (extraex IS NULL)', null, function (err, docs) { if (docs != null) { for (var i in docs) { if (docs[i].links != null) { docs[i] = common.unEscapeLinksFieldName(docs[i]); } } } - var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null) { r.push(docs[i]); } } } func(err, r); + var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null && docs[i].intelamt != null) { r.push(docs[i]); } } } func(err, r); }); }; obj.getAmtUuidMeshNode = function (domainid, mtype, uuid, func) { @@ -1470,36 +1672,102 @@ module.exports.CreateDB = function (parent, func) { obj.StoreEvent = function (event, func) { obj.dbCounters.eventsSet++; sqlDbQuery('INSERT INTO events VALUES (NULL, $1, $2, $3, $4, $5, $6) RETURNING id', [event.time, ((typeof event.domain == 'string') ? event.domain : null), event.action, event.nodeid ? event.nodeid : null, event.userid ? event.userid : null, JSON.stringify(event)], function (err, docs) { - if ((err == null) && (docs[0].id)) { for (var i in event.ids) { if (event.ids[i] != '*') { sqlDbQuery('INSERT INTO eventids VALUES ($1, $2)', [docs[0].id, event.ids[i]]); } } } + if(func){ func(); } + if ((err == null) && (docs[0].id)) { + for (var i in event.ids) { + if (event.ids[i] != '*') { + obj.pendingTransfer++; + sqlDbQuery('INSERT INTO eventids VALUES ($1, $2)', [docs[0].id, event.ids[i]], function(){ if(func){ func(); } }); + } + } + } }); }; - obj.GetEvents = function (ids, domain, func) { + obj.GetEvents = function (ids, domain, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1) ORDER BY time DESC', [domain], func); + query = query + "WHERE (domain = $1"; + if (filter != null) { + query = query + " AND action = $2"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC"; } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND (target IN (' + dbMergeSqlArray(ids) + '))) GROUP BY id ORDER BY time DESC', [domain], func); + query = query + 'JOIN eventids ON id = fkid WHERE (domain = $1 AND (target IN (' + dbMergeSqlArray(ids) + '))'; + if (filter != null) { + query = query + " AND action = $2"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC "; } + sqlDbQuery(query, dataarray, func); }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { + obj.GetEventsWithLimit = function (ids, domain, limit, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1) ORDER BY time DESC LIMIT $2', [domain, limit], func); + query = query + "WHERE (domain = $1"; + if (filter != null) { + query = query + " AND action = $2) ORDER BY time DESC LIMIT $3"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $2"; + } } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND (target IN (' + dbMergeSqlArray(ids) + '))) GROUP BY id ORDER BY time DESC LIMIT $2', [domain, limit], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = $1 AND (target IN (" + dbMergeSqlArray(ids) + "))"; + if (filter != null) { + query = query + " AND action = $2) GROUP BY id ORDER BY time DESC LIMIT $3"; + dataarray.push(filter); + } else { + query = query + ") GROUP BY id ORDER BY time DESC LIMIT $2"; + } } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); }; - obj.GetUserEvents = function (ids, domain, userid, func) { + obj.GetUserEvents = function (ids, domain, userid, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain, userid]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1 AND userid = $2) ORDER BY time DESC', [domain, userid], func); + query = query + "WHERE (domain = $1 AND userid = $2"; + if (filter != null) { + query = query + " AND action = $3"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC"; } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target IN (' + dbMergeSqlArray(ids) + '))) GROUP BY id ORDER BY time DESC', [domain, userid], func); + query = query + 'JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target IN (' + dbMergeSqlArray(ids) + '))'; + if (filter != null) { + query = query + " AND action = $3"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC"; } + sqlDbQuery(query, dataarray, func); }; - obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, func) { + obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain, userid]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1 AND userid = $2) ORDER BY time DESC LIMIT $3', [domain, userid, limit], func); + query = query + "WHERE (domain = $1 AND userid = $2"; + if (filter != null) { + query = query + " AND action = $3) ORDER BY time DESC LIMIT $4"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $3"; + } } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target IN (' + dbMergeSqlArray(ids) + '))) GROUP BY id ORDER BY time DESC LIMIT $3', [domain, userid, limit], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target IN (" + dbMergeSqlArray(ids) + "))"; + if (filter != null) { + query = query + " AND action = $3) GROUP BY id ORDER BY time DESC LIMIT $4"; + dataarray.push(filter); + } else { + query = query + ") GROUP BY id ORDER BY time DESC LIMIT $3"; + } } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); }; obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { if (ids.indexOf('*') >= 0) { @@ -1509,8 +1777,30 @@ module.exports.CreateDB = function (parent, func) { } }; //obj.GetUserLoginEvents = function (domain, userid, func) { } // TODO - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { sqlDbQuery('SELECT doc FROM events WHERE (nodeid = $1) AND (domain = $2) ORDER BY time DESC LIMIT $3', [nodeid, domain, limit], func); }; - obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { sqlDbQuery('SELECT doc FROM events WHERE (nodeid = $1) AND (domain = $2) AND ((userid = $3) OR (userid IS NULL)) ORDER BY time DESC LIMIT $4', [nodeid, domain, userid, limit], func); }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, filter, func) { + var query = "SELECT doc FROM events WHERE (nodeid = $1 AND domain = $2"; + var dataarray = [nodeid, domain]; + if (filter != null) { + query = query + " AND action = $3) ORDER BY time DESC LIMIT $4"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $3"; + } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); + }; + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, filter, func) { + var query = "SELECT doc FROM events WHERE (nodeid = $1) AND (domain = $2) AND ((userid = $3) OR (userid IS NULL)) "; + var dataarray = [nodeid, domain, userid]; + if (filter != null) { + query = query + "AND (action = $4) ORDER BY time DESC LIMIT $5"; + dataarray.push(filter); + } else { + query = query + "ORDER BY time DESC LIMIT $4"; + } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); + }; obj.RemoveAllEvents = function (domain) { sqlDbQuery('DELETE FROM events', null, function (err, docs) { }); }; obj.RemoveAllNodeEvents = function (domain, nodeid) { if ((domain == null) || (nodeid == null)) return; sqlDbQuery('DELETE FROM events WHERE domain = $1 AND nodeid = $2', [domain, nodeid], function (err, docs) { }); }; obj.RemoveAllUserEvents = function (domain, userid) { if ((domain == null) || (userid == null)) return; sqlDbQuery('DELETE FROM events WHERE domain = $1 AND userid = $2', [domain, userid], function (err, docs) { }); }; @@ -1553,14 +1843,14 @@ module.exports.CreateDB = function (parent, func) { // Plugin operations if (obj.pluginsActive) { - obj.addPlugin = function (plugin, func) { sqlDbQuery('INSERT INTO plugin VALUES (NULL, $1)', [JSON.stringify(value)], func); }; // Add a plugin - obj.getPlugins = function (func) { sqlDbQuery('SELECT doc FROM plugin', null, func); }; // Get all plugins - obj.getPlugin = function (id, func) { sqlDbQuery('SELECT doc FROM plugin WHERE id = $1', [id], func); }; // Get plugin + obj.addPlugin = function (plugin, func) { sqlDbQuery('INSERT INTO plugin VALUES (NULL, $1)', [JSON.stringify(plugin)], func); }; // Add a plugin + obj.getPlugins = function (func) { sqlDbQuery('SELECT JSON_INSERT(doc, "$._id", id) as doc FROM plugin', null, func); }; // Get all plugins + obj.getPlugin = function (id, func) { sqlDbQuery('SELECT JSON_INSERT(doc, "$._id", id) as doc FROM plugin WHERE id = $1', [id], func); }; // Get plugin obj.deletePlugin = function (id, func) { sqlDbQuery('DELETE FROM plugin WHERE id = $1', [id], func); }; // Delete plugin - obj.setPluginStatus = function (id, status, func) { obj.getPlugin(id, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].status = status; obj.updatePlugin(id, docs[0], func); } }); }; - obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('INSERT INTO plugin VALUES ($1, $2) ON CONFLICT (id) DO UPDATE SET doc = $2', [id, JSON.stringify(args)], func); }; + obj.setPluginStatus = function (id, status, func) { sqlDbQuery('UPDATE plugin SET doc=JSON_SET(doc,"$.status",$1) WHERE id=$2', [status,id], func); }; + obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('UPDATE plugin SET doc=json_patch(doc,$1) WHERE id=$2', [JSON.stringify(args),id], func); }; } - } else if (obj.databaseType == 7) { + } else if (obj.databaseType == DB_ACEBASE) { // Database actions on the main collection. AceBase: https://github.com/appy-one/acebase obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); @@ -1629,7 +1919,7 @@ module.exports.CreateDB = function (parent, func) { obj.RemoveMeshDocuments = function (id) { obj.file.query('meshcentral').filter('meshid', '==', id).remove(); obj.file.ref('meshcentral').child(encodeURIComponent('nt' + id)).remove(); }; obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; obj.DeleteDomain = function (domain, func) { obj.file.query('meshcentral').filter('domain', '==', domain).remove().then(function () { if (func) { func(); } }); }; - obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; + obj.SetUser = function (user) { if (user == null) return; if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; obj.getLocalAmtNodes = function (func) { obj.file.query('meshcentral').filter('type', '==', 'node').filter('host', 'exists').filter('host', '!=', null).filter('intelamt', 'exists').get(function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, performTypedRecordDecrypt(docs)); }); }; obj.getAmtUuidMeshNode = function (domainid, mtype, uuid, func) { obj.file.query('meshcentral').filter('type', '==', 'node').filter('domain', '==', domainid).filter('mtype', '!=', mtype).filter('intelamt.uuid', '==', uuid).get(function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, performTypedRecordDecrypt(docs)); }); }; @@ -1648,42 +1938,78 @@ module.exports.CreateDB = function (parent, func) { obj.dbCounters.eventsSet++; obj.file.ref('events').push(event).then(function (userRef) { if (func) { func(); } }); }; - obj.GetEvents = function (ids, domain, func) { + obj.GetEvents = function (ids, domain, filter, func) { // This request is slow since we have not found a .filter() that will take two arrays and match a single item. - obj.file.query('events').filter('domain', '==', domain).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type'] }, function (snapshots) { - const docs = []; - for (var i in snapshots) { - const doc = snapshots[i].val(); - if ((doc.ids == null) || (!Array.isArray(doc.ids))) continue; - var found = false; - for (var j in doc.ids) { if (ids.indexOf(doc.ids[j]) >= 0) { found = true; } } // Check if one of the items in both arrays matches - if (found) { delete doc.ids; if (typeof doc.account == 'object') { doc.account = common.aceUnEscapeFieldNames(doc.account); } docs.push(doc); } - } - func(null, docs); - }); + if (filter != null) { + obj.file.query('events').filter('domain', '==', domain).filter('action', '==', filter).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type'] }, function (snapshots) { + const docs = []; + for (var i in snapshots) { + const doc = snapshots[i].val(); + if ((doc.ids == null) || (!Array.isArray(doc.ids))) continue; + var found = false; + for (var j in doc.ids) { if (ids.indexOf(doc.ids[j]) >= 0) { found = true; } } // Check if one of the items in both arrays matches + if (found) { delete doc.ids; if (typeof doc.account == 'object') { doc.account = common.aceUnEscapeFieldNames(doc.account); } docs.push(doc); } + } + func(null, docs); + }); + } else { + obj.file.query('events').filter('domain', '==', domain).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type'] }, function (snapshots) { + const docs = []; + for (var i in snapshots) { + const doc = snapshots[i].val(); + if ((doc.ids == null) || (!Array.isArray(doc.ids))) continue; + var found = false; + for (var j in doc.ids) { if (ids.indexOf(doc.ids[j]) >= 0) { found = true; } } // Check if one of the items in both arrays matches + if (found) { delete doc.ids; if (typeof doc.account == 'object') { doc.account = common.aceUnEscapeFieldNames(doc.account); } docs.push(doc); } + } + func(null, docs); + }); + } }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { + obj.GetEventsWithLimit = function (ids, domain, limit, filter, func) { // This request is slow since we have not found a .filter() that will take two arrays and match a single item. // TODO: Request a new AceBase feature for a 'array:contains-one-of' filter: // obj.file.indexes.create('events', 'ids', { type: 'array' }); // db.query('events').filter('ids', 'array:contains-one-of', ids) - obj.file.query('events').filter('domain', '==', domain).take(limit).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type'] }, function (snapshots) { - const docs = []; - for (var i in snapshots) { - const doc = snapshots[i].val(); - if ((doc.ids == null) || (!Array.isArray(doc.ids))) continue; - var found = false; - for (var j in doc.ids) { if (ids.indexOf(doc.ids[j]) >= 0) { found = true; } } // Check if one of the items in both arrays matches - if (found) { delete doc.ids; if (typeof doc.account == 'object') { doc.account = common.aceUnEscapeFieldNames(doc.account); } docs.push(doc); } - } - func(null, docs); - }); + if (filter != null) { + obj.file.query('events').filter('domain', '==', domain).filter('action', '==', filter).take(limit).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type'] }, function (snapshots) { + const docs = []; + for (var i in snapshots) { + const doc = snapshots[i].val(); + if ((doc.ids == null) || (!Array.isArray(doc.ids))) continue; + var found = false; + for (var j in doc.ids) { if (ids.indexOf(doc.ids[j]) >= 0) { found = true; } } // Check if one of the items in both arrays matches + if (found) { delete doc.ids; if (typeof doc.account == 'object') { doc.account = common.aceUnEscapeFieldNames(doc.account); } docs.push(doc); } + } + func(null, docs); + }); + } else { + obj.file.query('events').filter('domain', '==', domain).take(limit).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type'] }, function (snapshots) { + const docs = []; + for (var i in snapshots) { + const doc = snapshots[i].val(); + if ((doc.ids == null) || (!Array.isArray(doc.ids))) continue; + var found = false; + for (var j in doc.ids) { if (ids.indexOf(doc.ids[j]) >= 0) { found = true; } } // Check if one of the items in both arrays matches + if (found) { delete doc.ids; if (typeof doc.account == 'object') { doc.account = common.aceUnEscapeFieldNames(doc.account); } docs.push(doc); } + } + func(null, docs); + }); + } }; - obj.GetUserEvents = function (ids, domain, userid, func) { - obj.file.query('events').filter('domain', '==', domain).filter('userid', 'in', userid).filter('ids', 'in', ids).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type', 'ids'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + obj.GetUserEvents = function (ids, domain, userid, filter, func) { + if (filter != null) { + obj.file.query('events').filter('domain', '==', domain).filter('userid', 'in', userid).filter('ids', 'in', ids).filter('action', '==', filter).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type', 'ids'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } else { + obj.file.query('events').filter('domain', '==', domain).filter('userid', 'in', userid).filter('ids', 'in', ids).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type', 'ids'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } }; - obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, func) { - obj.file.query('events').take(limit).filter('domain', '==', domain).filter('userid', 'in', userid).filter('ids', 'in', ids).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type', 'ids'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, filter, func) { + if (filter != null) { + obj.file.query('events').take(limit).filter('domain', '==', domain).filter('userid', 'in', userid).filter('ids', 'in', ids).filter('action', '==', filter).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type', 'ids'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } else { + obj.file.query('events').take(limit).filter('domain', '==', domain).filter('userid', 'in', userid).filter('ids', 'in', ids).sort('time', false).get({ exclude: ['_id', 'domain', 'node', 'type', 'ids'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } }; obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { obj.file.query('events').filter('domain', '==', domain).filter('ids', 'in', ids).filter('msgid', 'in', msgids).filter('time', 'between', [start, end]).sort('time', false).get({ exclude: ['type', '_id', 'domain', 'node'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); @@ -1691,10 +2017,19 @@ module.exports.CreateDB = function (parent, func) { obj.GetUserLoginEvents = function (domain, userid, func) { obj.file.query('events').filter('domain', '==', domain).filter('action', 'in', ['authfail', 'login']).filter('userid', '==', userid).filter('msgArgs', 'exists').sort('time', false).get({ include: ['action', 'time', 'msgid', 'msgArgs', 'tokenName'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); }; - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { - obj.file.query('events').take(limit).filter('domain', '==', domain).filter('nodeid', '==', nodeid).sort('time', false).get({ exclude: ['type', 'etype', '_id', 'domain', 'ids', 'node', 'nodeid'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, filter, func) { + if (filter != null) { + obj.file.query('events').take(limit).filter('domain', '==', domain).filter('nodeid', '==', nodeid).filter('action', '==', filter).sort('time', false).get({ exclude: ['type', 'etype', '_id', 'domain', 'ids', 'node', 'nodeid'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } else { + obj.file.query('events').take(limit).filter('domain', '==', domain).filter('nodeid', '==', nodeid).sort('time', false).get({ exclude: ['type', 'etype', '_id', 'domain', 'ids', 'node', 'nodeid'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } }; - obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, filter, func) { + if (filter != null) { + obj.file.query('events').take(limit).filter('domain', '==', domain).filter('nodeid', '==', nodeid).filter('userid', '==', userid).filter('action', '==', filter).sort('time', false).get({ exclude: ['type', 'etype', '_id', 'domain', 'ids', 'node', 'nodeid'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } else { + obj.file.query('events').take(limit).filter('domain', '==', domain).filter('nodeid', '==', nodeid).filter('userid', '==', userid).sort('time', false).get({ exclude: ['type', 'etype', '_id', 'domain', 'ids', 'node', 'nodeid'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); + } obj.file.query('events').take(limit).filter('domain', '==', domain).filter('nodeid', '==', nodeid).filter('userid', '==', userid).sort('time', false).get({ exclude: ['type', 'etype', '_id', 'domain', 'ids', 'node', 'nodeid'] }, function (snapshots) { const docs = []; for (var i in snapshots) { docs.push(snapshots[i].val()); } func(null, docs); }); }; obj.RemoveAllEvents = function (domain) { @@ -1807,7 +2142,7 @@ module.exports.CreateDB = function (parent, func) { obj.setPluginStatus = function (id, status, func) { obj.file.ref('plugin').child(encodeURIComponent(id)).update({ status: status }).then(function (ref) { if (func) { func(); } }) }; obj.updatePlugin = function (id, args, func) { delete args._id; obj.file.ref('plugin').child(encodeURIComponent(id)).set(args).then(function (ref) { if (func) { func(); } }) }; } - } else if (obj.databaseType == 6) { + } else if (obj.databaseType == DB_POSTGRESQL) { // Database actions on the main collection (Postgres) obj.Set = function (value, func) { obj.dbCounters.fileSet++; @@ -1871,9 +2206,9 @@ module.exports.CreateDB = function (parent, func) { obj.RemoveMeshDocuments = function (id, func) { sqlDbQuery('DELETE FROM main WHERE extra = $1', [id], function () { sqlDbQuery('DELETE FROM main WHERE id = $1', ['nt' + id], func); }); }; obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; obj.DeleteDomain = function (domain, func) { sqlDbQuery('DELETE FROM main WHERE domain = $1', [domain], func); }; - obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; + obj.SetUser = function (user) { if (user == null) return; if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; - obj.getLocalAmtNodes = function (func) { sqlDbQuery('SELECT doc FROM main WHERE (type = \'node\') AND (extraex IS NOT NULL)', null, function (err, docs) { var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null) { r.push(docs[i]); } } } func(err, r); }); }; + obj.getLocalAmtNodes = function (func) { sqlDbQuery('SELECT doc FROM main WHERE (type = \'node\') AND (extraex IS NULL)', null, function (err, docs) { var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null && docs[i].intelamt != null) { r.push(docs[i]); } } } func(err, r); }); }; obj.getAmtUuidMeshNode = function (domainid, mtype, uuid, func) { sqlDbQuery('SELECT doc FROM main WHERE domain = $1 AND extraex = $2', [domainid, 'uuid/' + uuid], func); }; obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { sqlDbExec('SELECT COUNT(id) FROM main WHERE domain = $1 AND type = $2', [domainid, type], function (err, response) { func((response['COUNT(id)'] == null) || (response['COUNT(id)'] > max), response['COUNT(id)']) }); } } @@ -1882,36 +2217,109 @@ module.exports.CreateDB = function (parent, func) { obj.StoreEvent = function (event, func) { obj.dbCounters.eventsSet++; sqlDbQuery('INSERT INTO events VALUES (DEFAULT, $1, $2, $3, $4, $5, $6) RETURNING id', [event.time, ((typeof event.domain == 'string') ? event.domain : null), event.action, event.nodeid ? event.nodeid : null, event.userid ? event.userid : null, event], function (err, docs) { - if (docs.id) { for (var i in event.ids) { if (event.ids[i] != '*') { sqlDbQuery('INSERT INTO eventids VALUES ($1, $2)', [docs.id, event.ids[i]]); } } } + if(func){ func(); } + if (docs.id) { + for (var i in event.ids) { + if (event.ids[i] != '*') { + obj.pendingTransfer++; + sqlDbQuery('INSERT INTO eventids VALUES ($1, $2)', [docs.id, event.ids[i]], function(){ if(func){ func(); } }); + } + } + } }); }; - obj.GetEvents = function (ids, domain, func) { + obj.GetEvents = function (ids, domain, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1) ORDER BY time DESC', [domain], func); + query = query + "WHERE (domain = $1"; + if (filter != null) { + query = query + " AND action = $2"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC"; } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND (target = ANY ($2))) GROUP BY id ORDER BY time DESC', [domain, ids], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = $1 AND (target = ANY ($2))"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = $3"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC"; } + sqlDbQuery(query, dataarray, func); }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { + obj.GetEventsWithLimit = function (ids, domain, limit, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1) ORDER BY time DESC LIMIT $2', [domain, limit], func); + query = query + "WHERE (domain = $1"; + if (filter != null) { + query = query + " AND action = $2) ORDER BY time DESC LIMIT $3"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $2"; + } } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND (target = ANY ($2))) GROUP BY id ORDER BY time DESC LIMIT $3', [domain, ids, limit], func); + if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. + query = query + "JOIN eventids ON id = fkid WHERE (domain = $1 AND (target = ANY ($2))"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = $3) ORDER BY time DESC LIMIT $4"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $3"; + } } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); }; - obj.GetUserEvents = function (ids, domain, userid, func) { + obj.GetUserEvents = function (ids, domain, userid, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain, userid]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1 AND userid = $2) ORDER BY time DESC', [domain, userid], func); + query = query + "WHERE (domain = $1 AND userid = $2"; + if (filter != null) { + query = query + " AND action = $3"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC"; } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target = ANY ($3))) GROUP BY id ORDER BY time DESC', [domain, userid, ids], func); + if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. + query = query + "JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target = ANY ($3))"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = $4"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC"; } + sqlDbQuery(query, dataarray, func); }; - obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, func) { + obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain, userid]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = $1 AND userid = $2) ORDER BY time DESC LIMIT $3', [domain, userid, limit], func); + query = query + "WHERE (domain = $1 AND userid = $2"; + if (filter != null) { + query = query + " AND action = $3) ORDER BY time DESC LIMIT $4 "; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $3"; + } } else { - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target = ANY ($3))) GROUP BY id ORDER BY time DESC LIMIT $4', [domain, userid, ids, limit], func); + if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. + query = query + "JOIN eventids ON id = fkid WHERE (domain = $1 AND userid = $2 AND (target = ANY ($3))"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = $4) GROUP BY id ORDER BY time DESC LIMIT $5"; + dataarray.push(filter); + } else { + query = query + ") GROUP BY id ORDER BY time DESC LIMIT $4"; + } } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); }; obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { if (ids.indexOf('*') >= 0) { @@ -1921,8 +2329,30 @@ module.exports.CreateDB = function (parent, func) { } }; //obj.GetUserLoginEvents = function (domain, userid, func) { } // TODO - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { sqlDbQuery('SELECT doc FROM events WHERE (nodeid = $1) AND (domain = $2) ORDER BY time DESC LIMIT $3', [nodeid, domain, limit], func); }; - obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { sqlDbQuery('SELECT doc FROM events WHERE (nodeid = $1) AND (domain = $2) AND ((userid = $3) OR (userid IS NULL)) ORDER BY time DESC LIMIT $4', [nodeid, domain, userid, limit], func); }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, filter, func) { + var query = "SELECT doc FROM events WHERE (nodeid = $1 AND domain = $2"; + var dataarray = [nodeid, domain]; + if (filter != null) { + query = query + " AND action = $3) ORDER BY time DESC LIMIT $4"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $3"; + } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); + }; + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, filter, func) { + var query = "SELECT doc FROM events WHERE (nodeid = $1 AND domain = $2 AND ((userid = $3) OR (userid IS NULL))"; + var dataarray = [nodeid, domain, userid]; + if (filter != null) { + query = query + " AND action = $4) ORDER BY time DESC LIMIT $5"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT $4"; + } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); + }; obj.RemoveAllEvents = function (domain) { sqlDbQuery('DELETE FROM events', null, function (err, docs) { }); }; obj.RemoveAllNodeEvents = function (domain, nodeid) { if ((domain == null) || (nodeid == null)) return; sqlDbQuery('DELETE FROM events WHERE domain = $1 AND nodeid = $2', [domain, nodeid], function (err, docs) { }); }; obj.RemoveAllUserEvents = function (domain, userid) { if ((domain == null) || (userid == null)) return; sqlDbQuery('DELETE FROM events WHERE domain = $1 AND userid = $2', [domain, userid], function (err, docs) { }); }; @@ -1965,14 +2395,14 @@ module.exports.CreateDB = function (parent, func) { // Plugin operations if (obj.pluginsActive) { - obj.addPlugin = function (plugin, func) { sqlDbQuery('INSERT INTO plugin VALUES (DEFAULT, $2)', [value], func); }; // Add a plugin - obj.getPlugins = function (func) { sqlDbQuery('SELECT doc FROM plugin', null, func); }; // Get all plugins - obj.getPlugin = function (id, func) { sqlDbQuery('SELECT doc FROM plugin WHERE id = $1', [id], func); }; // Get plugin + obj.addPlugin = function (plugin, func) { sqlDbQuery('INSERT INTO plugin VALUES (DEFAULT, $1)', [plugin], func); }; // Add a plugin + obj.getPlugins = function (func) { sqlDbQuery("SELECT doc::jsonb || ('{\"_id\":' || plugin.id || '}')::jsonb as doc FROM plugin", null, func); }; // Get all plugins + obj.getPlugin = function (id, func) { sqlDbQuery("SELECT doc::jsonb || ('{\"_id\":' || plugin.id || '}')::jsonb as doc FROM plugin WHERE id = $1", [id], func); }; // Get plugin obj.deletePlugin = function (id, func) { sqlDbQuery('DELETE FROM plugin WHERE id = $1', [id], func); }; // Delete plugin - obj.setPluginStatus = function (id, status, func) { obj.getPlugin(id, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].status = status; obj.updatePlugin(id, docs[0], func); } }); }; - obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('INSERT INTO plugin VALUES ($1, $2) ON CONFLICT (id) DO UPDATE SET doc = $2', [id, args], func); }; + obj.setPluginStatus = function (id, status, func) { sqlDbQuery("UPDATE plugin SET doc= jsonb_set(doc::jsonb,'{status}',$1) WHERE id=$2", [status,id], func); }; + obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('UPDATE plugin SET doc= doc::jsonb || ($1) WHERE id=$2', [args,id], func); }; } - } else if ((obj.databaseType == 4) || (obj.databaseType == 5)) { + } else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) { // Database actions on the main collection (MariaDB or MySQL) obj.Set = function (value, func) { obj.dbCounters.fileSet++; @@ -2036,9 +2466,9 @@ module.exports.CreateDB = function (parent, func) { obj.RemoveMeshDocuments = function (id, func) { sqlDbQuery('DELETE FROM main WHERE extra = ?', [id], function () { sqlDbQuery('DELETE FROM main WHERE id = ?', ['nt' + id], func); } ); }; obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; obj.DeleteDomain = function (domain, func) { sqlDbQuery('DELETE FROM main WHERE domain = ?', [domain], func); }; - obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; + obj.SetUser = function (user) { if (user == null) return; if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; - obj.getLocalAmtNodes = function (func) { sqlDbQuery('SELECT doc FROM main WHERE (type = "node") AND (extraex IS NOT NULL)', null, function (err, docs) { var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null) { r.push(docs[i]); } } } func(err, r); }); }; + obj.getLocalAmtNodes = function (func) { sqlDbQuery('SELECT doc FROM main WHERE (type = "node") AND (extraex IS NULL)', null, function (err, docs) { var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null && docs[i].intelamt != null) { r.push(docs[i]); } } } func(err, r); }); }; obj.getAmtUuidMeshNode = function (domainid, mtype, uuid, func) { sqlDbQuery('SELECT doc FROM main WHERE domain = ? AND extraex = ?', [domainid, 'uuid/' + uuid], func); }; obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { sqlDbExec('SELECT COUNT(id) FROM main WHERE domain = ? AND type = ?', [domainid, type], function (err, response) { func((response['COUNT(id)'] == null) || (response['COUNT(id)'] > max), response['COUNT(id)']) }); } } @@ -2050,37 +2480,95 @@ module.exports.CreateDB = function (parent, func) { for (var i in event.ids) { if (event.ids[i] != '*') { batchQuery.push(['INSERT INTO eventids VALUE (LAST_INSERT_ID(), ?)', [event.ids[i]]]); } } sqlDbBatchExec(batchQuery, function (err, docs) { if (func != null) { func(err, docs); } }); }; - obj.GetEvents = function (ids, domain, func) { + obj.GetEvents = function (ids, domain, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = ?) ORDER BY time DESC', [domain], func); + query = query + "WHERE (domain = ?"; + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC"; } else { if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = ? AND target IN (?)) GROUP BY id ORDER BY time DESC', [domain, ids], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = ? AND target IN (?)"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC"; } + sqlDbQuery(query, dataarray, func); }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { + obj.GetEventsWithLimit = function (ids, domain, limit, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = ?) ORDER BY time DESC LIMIT ?', [domain, limit], func); + query = query + "WHERE (domain = ?"; + if (filter != null) { + query = query + " AND action = ? "; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC LIMIT ?"; } else { if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = ? AND target IN (?)) GROUP BY id ORDER BY time DESC LIMIT ?', [domain, ids, limit], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = ? AND target IN (?)"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC LIMIT ?"; } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); }; - obj.GetUserEvents = function (ids, domain, userid, func) { + obj.GetUserEvents = function (ids, domain, userid, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain, userid]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = ? AND userid = ?) ORDER BY time DESC', [domain, userid], func); + query = query + "WHERE (domain = ? AND userid = ?"; + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC"; } else { if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = ? AND userid = ? AND target IN (?)) GROUP BY id ORDER BY time DESC', [domain, userid, ids], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = ? AND userid = ? AND target IN (?)"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC"; } + sqlDbQuery(query, dataarray, func); }; - obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, func) { + obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, filter, func) { + var query = "SELECT doc FROM events "; + var dataarray = [domain, userid]; if (ids.indexOf('*') >= 0) { - sqlDbQuery('SELECT doc FROM events WHERE (domain = ? AND userid = ?) ORDER BY time DESC LIMIT ?', [domain, userid, limit], func); + query = query + "WHERE (domain = ? AND userid = ?"; + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") ORDER BY time DESC LIMIT ?"; } else { if (ids.length == 0) { ids = ''; } // MySQL can't handle a query with IN() on an empty array, we have to use an empty string instead. - sqlDbQuery('SELECT doc FROM events JOIN eventids ON id = fkid WHERE (domain = ? AND userid = ? AND target IN (?)) GROUP BY id ORDER BY time DESC LIMIT ?', [domain, userid, ids, limit], func); + query = query + "JOIN eventids ON id = fkid WHERE (domain = ? AND userid = ? AND target IN (?)"; + dataarray.push(ids); + if (filter != null) { + query = query + " AND action = ?"; + dataarray.push(filter); + } + query = query + ") GROUP BY id ORDER BY time DESC LIMIT ?"; } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); }; obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { if (ids.indexOf('*') >= 0) { @@ -2091,8 +2579,30 @@ module.exports.CreateDB = function (parent, func) { } }; //obj.GetUserLoginEvents = function (domain, userid, func) { } // TODO - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { sqlDbQuery('SELECT doc FROM events WHERE (nodeid = ?) AND (domain = ?) ORDER BY time DESC LIMIT ?', [nodeid, domain, limit], func); }; - obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { sqlDbQuery('SELECT doc FROM events WHERE (nodeid = ?) AND (domain = ?) AND ((userid = ?) OR (userid IS NULL)) ORDER BY time DESC LIMIT ?', [nodeid, domain, userid, limit], func); }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, filter, func) { + var query = "SELECT doc FROM events WHERE (nodeid = ? AND domain = ?"; + var dataarray = [nodeid, domain]; + if (filter != null) { + query = query + " AND action = ?) ORDER BY time DESC LIMIT ?"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT ?"; + } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); + }; + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, filter, func) { + var query = "SELECT doc FROM events WHERE (nodeid = ? AND domain = ? AND ((userid = ?) OR (userid IS NULL))"; + var dataarray = [nodeid, domain, userid]; + if (filter != null) { + query = query + " AND action = ?) ORDER BY time DESC LIMIT ?"; + dataarray.push(filter); + } else { + query = query + ") ORDER BY time DESC LIMIT ?"; + } + dataarray.push(limit); + sqlDbQuery(query, dataarray, func); + }; obj.RemoveAllEvents = function (domain) { sqlDbQuery('DELETE FROM events', null, function (err, docs) { }); }; obj.RemoveAllNodeEvents = function (domain, nodeid) { if ((domain == null) || (nodeid == null)) return; sqlDbQuery('DELETE FROM events WHERE domain = ? AND nodeid = ?', [domain, nodeid], function (err, docs) { }); }; obj.RemoveAllUserEvents = function (domain, userid) { if ((domain == null) || (userid == null)) return; sqlDbQuery('DELETE FROM events WHERE domain = ? AND userid = ?', [domain, userid], function (err, docs) { }); }; @@ -2135,14 +2645,14 @@ module.exports.CreateDB = function (parent, func) { // Plugin operations if (obj.pluginsActive) { - obj.addPlugin = function (plugin, func) { sqlDbQuery('INSERT INTO plugin VALUE (?, ?)', [null, JSON.stringify(value)], func); }; // Add a plugin - obj.getPlugins = function (func) { sqlDbQuery('SELECT doc FROM plugin', null, func); }; // Get all plugins - obj.getPlugin = function (id, func) { sqlDbQuery('SELECT doc FROM plugin WHERE id = ?', [id], func); }; // Get plugin + obj.addPlugin = function (plugin, func) { sqlDbQuery('INSERT INTO plugin VALUE (?, ?)', [null, JSON.stringify(plugin)], func); }; // Add a plugin + obj.getPlugins = function (func) { sqlDbQuery('SELECT JSON_INSERT(doc, "$._id", id) as doc FROM plugin', null, func); }; // Get all plugins + obj.getPlugin = function (id, func) { sqlDbQuery('SELECT JSON_INSERT(doc, "$._id", id) as doc FROM plugin WHERE id = ?', [id], func); }; // Get plugin obj.deletePlugin = function (id, func) { sqlDbQuery('DELETE FROM plugin WHERE id = ?', [id], func); }; // Delete plugin - obj.setPluginStatus = function (id, status, func) { obj.getPlugin(id, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].status = status; obj.updatePlugin(id, docs[0], func); } }); }; - obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('REPLACE INTO plugin VALUE (?, ?)', [id, JSON.stringify(args)], func); }; + obj.setPluginStatus = function (id, status, func) { sqlDbQuery('UPDATE meshcentral.plugin SET doc=JSON_SET(doc,"$.status",?) WHERE id=?', [status,id], func); }; + obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('UPDATE meshcentral.plugin SET doc=JSON_MERGE_PATCH(doc,?) WHERE id=?', [JSON.stringify(args),id], func); }; } - } else if (obj.databaseType == 3) { + } else if (obj.databaseType == DB_MONGODB) { // Database actions on the main collection (MongoDB) // Bulk operations @@ -2287,7 +2797,7 @@ module.exports.CreateDB = function (parent, func) { obj.RemoveMeshDocuments = function (id) { obj.file.deleteMany({ meshid: id }, { multi: true }); obj.file.deleteOne({ _id: 'nt' + id }); }; obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; obj.DeleteDomain = function (domain, func) { obj.file.deleteMany({ domain: domain }, { multi: true }, func); }; - obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; + obj.SetUser = function (user) { if (user == null) return; if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }).toArray(func); }; obj.getAmtUuidMeshNode = function (domainid, mtype, uuid, func) { obj.file.find({ type: 'node', domain: domainid, mtype: mtype, 'intelamt.uuid': uuid }).toArray(func); }; @@ -2327,14 +2837,38 @@ module.exports.CreateDB = function (parent, func) { obj.StoreEvent = function (event, func) { obj.dbCounters.eventsSet++; obj.eventsfile.insertOne(event, func); }; } - obj.GetEvents = function (ids, domain, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; - obj.GetUserEvents = function (ids, domain, userid, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); }; - obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; + obj.GetEvents = function (ids, domain, filter, func) { + var finddata = { domain: domain, ids: { $in: ids } }; + if (filter != null) finddata.action = filter; + obj.eventsfile.find(finddata).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); + }; + obj.GetEventsWithLimit = function (ids, domain, limit, filter, func) { + var finddata = { domain: domain, ids: { $in: ids } }; + if (filter != null) finddata.action = filter; + obj.eventsfile.find(finddata).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); + }; + obj.GetUserEvents = function (ids, domain, userid, filter, func) { + var finddata = { domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }; + if (filter != null) finddata.action = filter; + obj.eventsfile.find(finddata).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); + }; + obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, filter, func) { + var finddata = { domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }; + if (filter != null) finddata.action = filter; + obj.eventsfile.find(finddata).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); + }; obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }], msgid: { $in: msgids }, time: { $gte: start, $lte: end } }).project({ type: 0, _id: 0, domain: 0, node: 0 }).sort({ time: 1 }).toArray(func); }; obj.GetUserLoginEvents = function (domain, userid, func) { obj.eventsfile.find({ domain: domain, action: { $in: ['authfail', 'login'] }, userid: userid, msgArgs: { $exists: true } }).project({ action: 1, time: 1, msgid: 1, msgArgs: 1, tokenName: 1 }).sort({ time: -1 }).toArray(func); }; - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; - obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, filter, func) { + var finddata = { domain: domain, nodeid: nodeid }; + if (filter != null) finddata.action = filter; + obj.eventsfile.find(finddata).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); + }; + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, filter, func) { + var finddata = { domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }; + if (filter != null) finddata.action = filter; + obj.eventsfile.find(finddata).project({ type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); + }; obj.RemoveAllEvents = function (domain) { obj.eventsfile.deleteMany({ domain: domain }, { multi: true }); }; obj.RemoveAllNodeEvents = function (domain, nodeid) { if ((domain == null) || (nodeid == null)) return; obj.eventsfile.deleteMany({ domain: domain, nodeid: nodeid }, { multi: true }); }; obj.RemoveAllUserEvents = function (domain, userid) { if ((domain == null) || (userid == null)) return; obj.eventsfile.deleteMany({ domain: domain, userid: userid }, { multi: true }); }; @@ -2490,7 +3024,7 @@ module.exports.CreateDB = function (parent, func) { obj.RemoveMeshDocuments = function (id) { obj.file.remove({ meshid: id }, { multi: true }); obj.file.remove({ _id: 'nt' + id }); }; obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); }; - obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; + obj.SetUser = function (user) { if (user == null) return; if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } }; obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); }; obj.getAmtUuidMeshNode = function (domainid, mtype, uuid, func) { obj.file.find({ type: 'node', domain: domainid, mtype: mtype, 'intelamt.uuid': uuid }, func); }; @@ -2499,38 +3033,74 @@ module.exports.CreateDB = function (parent, func) { // Database actions on the events collection obj.GetAllEvents = function (func) { obj.eventsfile.find({}, func); }; obj.StoreEvent = function (event, func) { obj.eventsfile.insert(event, func); }; - obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); } }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }; - obj.GetUserEvents = function (ids, domain, userid, func) { - if (obj.databaseType == 1) { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); + obj.GetEvents = function (ids, domain, filter, func) { + var finddata = { domain: domain, ids: { $in: ids } }; + if (filter != null) finddata.action = filter; + if (obj.databaseType == DB_NEDB) { + obj.eventsfile.find(finddata, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); + obj.eventsfile.find(finddata, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); } }; - obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, func) { - if (obj.databaseType == 1) { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); + obj.GetEventsWithLimit = function (ids, domain, limit, filter, func) { + var finddata = { domain: domain, ids: { $in: ids } }; + if (filter != null) finddata.action = filter; + if (obj.databaseType == DB_NEDB) { + obj.eventsfile.find(finddata, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); + obj.eventsfile.find(finddata, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); + } + }; + obj.GetUserEvents = function (ids, domain, userid, filter, func) { + var finddata = { domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }; + if (filter != null) finddata.action = filter; + if (obj.databaseType == DB_NEDB) { + obj.eventsfile.find(finddata, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); + } else { + obj.eventsfile.find(finddata, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); + } + }; + obj.GetUserEventsWithLimit = function (ids, domain, userid, limit, filter, func) { + var finddata = { domain: domain, $or: [{ ids: { $in: ids } }, { userid: userid }] }; + if (filter != null) finddata.action = filter; + if (obj.databaseType == DB_NEDB) { + obj.eventsfile.find(finddata, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); + } else { + obj.eventsfile.find(finddata, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }; obj.GetEventsTimeRange = function (ids, domain, msgids, start, end, func) { - if (obj.databaseType == 1) { + if (obj.databaseType == DB_NEDB) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }], msgid: { $in: msgids }, time: { $gte: start, $lte: end } }, { type: 0, _id: 0, domain: 0, node: 0 }).sort({ time: 1 }).exec(func); } else { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }], msgid: { $in: msgids }, time: { $gte: start, $lte: end } }, { type: 0, _id: 0, domain: 0, node: 0 }).sort({ time: 1 }, func); } }; obj.GetUserLoginEvents = function (domain, userid, func) { - if (obj.databaseType == 1) { + if (obj.databaseType == DB_NEDB) { obj.eventsfile.find({ domain: domain, action: { $in: ['authfail', 'login'] }, userid: userid, msgArgs: { $exists: true } }, { action: 1, time: 1, msgid: 1, msgArgs: 1, tokenName: 1 }).sort({ time: -1 }).exec(func); } else { obj.eventsfile.find({ domain: domain, action: { $in: ['authfail', 'login'] }, userid: userid, msgArgs: { $exists: true } }, { action: 1, time: 1, msgid: 1, msgArgs: 1, tokenName: 1 }).sort({ time: -1 }, func); } }; - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } }; - obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, filter, func) { + var finddata = { domain: domain, nodeid: nodeid }; + if (filter != null) finddata.action = filter; + if (obj.databaseType == DB_NEDB) { + obj.eventsfile.find(finddata, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); + } else { + obj.eventsfile.find(finddata, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); + } + }; + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, filter, func) { + var finddata = { domain: domain, nodeid: nodeid, userid: { $in: [userid, null] } }; + if (filter != null) finddata.action = filter; + if (obj.databaseType == DB_NEDB) { + obj.eventsfile.find(finddata, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); + } else { + obj.eventsfile.find(finddata, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); + } + }; obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); }; obj.RemoveAllNodeEvents = function (domain, nodeid) { if ((domain == null) || (nodeid == null)) return; obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); }; obj.RemoveAllUserEvents = function (domain, userid) { if ((domain == null) || (userid == null)) return; obj.eventsfile.remove({ domain: domain, userid: userid }, { multi: true }); }; @@ -2539,7 +3109,7 @@ module.exports.CreateDB = function (parent, func) { // Database actions on the power collection obj.getAllPower = function (func) { obj.powerfile.find({}, func); }; obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insert(event, func); }; - obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == 1) { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).exec(func); } else { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }, func); } }; + obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == DB_NEDB) { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).exec(func); } else { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }, func); } }; obj.removeAllPowerEvents = function () { obj.powerfile.remove({}, { multi: true }); }; obj.removeAllPowerEventsForNode = function (nodeid) { if (nodeid == null) return; obj.powerfile.remove({ nodeid: nodeid }, { multi: true }); }; @@ -2617,58 +3187,94 @@ module.exports.CreateDB = function (parent, func) { // Return a human readable string with current backup configuration obj.getBackupConfig = function () { var r = '', backupPath = parent.backuppath; - if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; } - var dbname = 'meshcentral'; + let dbname = 'meshcentral'; if (parent.args.mongodbname) { dbname = parent.args.mongodbname; } else if ((typeof parent.args.mariadb == 'object') && (typeof parent.args.mariadb.database == 'string')) { dbname = parent.args.mariadb.database; } else if ((typeof parent.args.mysql == 'object') && (typeof parent.args.mysql.database == 'string')) { dbname = parent.args.mysql.database; } + else if (typeof parent.config.settings.sqlite3 == 'string') {dbname = parent.config.settings.sqlite3 + '.sqlite'}; const currentDate = new Date(); const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2); - const newAutoBackupFile = 'meshcentral-autobackup-' + fileSuffix; - const newAutoBackupPath = parent.path.join(backupPath, newAutoBackupFile); + obj.newAutoBackupFile = parent.config.settings.autobackup.backupname + fileSuffix; r += 'DB Name: ' + dbname + '\r\n'; - r += 'DB Type: ' + ['None', 'NeDB', 'MongoJS', 'MongoDB', 'MariaDB', 'MySQL', 'AceBase'][obj.databaseType] + '\r\n'; + r += 'DB Type: ' + DB_LIST[obj.databaseType] + '\r\n'; r += 'BackupPath: ' + backupPath + '\r\n'; - r += 'newAutoBackupFile: ' + newAutoBackupFile + '\r\n'; - r += 'newAutoBackupPath: ' + newAutoBackupPath + '\r\n'; + r += 'BackupFile: ' + obj.newAutoBackupFile + '.zip\r\n'; if (parent.config.settings.autobackup == null) { r += 'No Settings/AutoBackup\r\n'; } else { + if (parent.config.settings.autobackup.backuphour != null && parent.config.settings.autobackup.backuphour != -1) { + r += 'Backup between: ' + parent.config.settings.autobackup.backuphour + 'H-' + (parent.config.settings.autobackup.backuphour + 1) + 'H\r\n'; + } if (parent.config.settings.autobackup.backupintervalhours != null) { - if (typeof parent.config.settings.autobackup.backupintervalhours != 'number') { r += 'Bad backupintervalhours type\r\n'; } - else { r += 'Backup Interval (Hours): ' + parent.config.settings.autobackup.backupintervalhours + '\r\n'; } + r += 'Backup Interval (Hours): ' + parent.config.settings.autobackup.backupintervalhours + '\r\n'; } if (parent.config.settings.autobackup.keeplastdaysbackup != null) { - if (typeof parent.config.settings.autobackup.keeplastdaysbackup != 'number') { r += 'Bad keeplastdaysbackup type\r\n'; } - else { r += 'Keep Last Backups (Days): ' + parent.config.settings.autobackup.keeplastdaysbackup + '\r\n'; } + r += 'Keep Last Backups (Days): ' + parent.config.settings.autobackup.keeplastdaysbackup + '\r\n'; } if (parent.config.settings.autobackup.zippassword != null) { - if (typeof parent.config.settings.autobackup.zippassword != 'string') { r += 'Bad zippassword type\r\n'; } - else { r += 'ZIP Password Set\r\n'; } + r += 'ZIP Password: '; + if (typeof parent.config.settings.autobackup.zippassword != 'string') { r += 'Bad zippassword type, Backups will not be encrypted\r\n'; } + else if (parent.config.settings.autobackup.zippassword == "") { r += 'Blank zippassword, Backups will fail\r\n'; } + else { r += 'Set\r\n'; } } if (parent.config.settings.autobackup.mongodumppath != null) { + r += 'MongoDump Path: '; if (typeof parent.config.settings.autobackup.mongodumppath != 'string') { r += 'Bad mongodumppath type\r\n'; } - else { r += 'MongoDump Path: ' + parent.config.settings.autobackup.mongodumppath + '\r\n'; } + else { r += parent.config.settings.autobackup.mongodumppath + '\r\n'; } } if (parent.config.settings.autobackup.mysqldumppath != null) { + r += 'MySqlDump Path: '; if (typeof parent.config.settings.autobackup.mysqldumppath != 'string') { r += 'Bad mysqldump type\r\n'; } - else { r += 'MySqlDump Path: ' + parent.config.settings.autobackup.mysqldumppath + '\r\n'; } + else { r += parent.config.settings.autobackup.mysqldumppath + '\r\n'; } } + if (parent.config.settings.autobackup.backupotherfolders) { + r += 'Backup other folders: '; + r += parent.filespath + ', ' + parent.recordpath + '\r\n'; + } + if (parent.config.settings.autobackup.backupwebfolders) { + r += 'Backup webfolders: '; + if (parent.webViewsOverridePath) {r += parent.webViewsOverridePath }; + if (parent.webPublicOverridePath) {r += ', '+ parent.webPublicOverridePath}; + if (parent.webEmailsOverridePath) {r += ',' + parent.webEmailsOverridePath}; + r+= '\r\n'; + } + if (parent.config.settings.autobackup.backupignorefilesglob != []) { + r += 'Backup IgnoreFilesGlob: '; + { r += parent.config.settings.autobackup.backupignorefilesglob + '\r\n'; } + } + if (parent.config.settings.autobackup.backupskipfoldersglob != []) { + r += 'Backup SkipFoldersGlob: '; + { r += parent.config.settings.autobackup.backupskipfoldersglob + '\r\n'; } + } + + if (typeof parent.config.settings.autobackup.s3 == 'object') { + r += 'S3 Backups: Enabled\r\n'; + } + if (typeof parent.config.settings.autobackup.webdav == 'object') { + r += 'WebDAV Backups: Enabled\r\n'; + r += 'WebDAV backup path: ' + ((typeof parent.config.settings.autobackup.webdav.foldername == 'string') ? parent.config.settings.autobackup.webdav.foldername : 'MeshCentral-Backups') + '\r\n'; + r += 'WebDAV maximum files: '+ ((typeof parent.config.settings.autobackup.webdav.maxfiles == 'number') ? parent.config.settings.autobackup.webdav.maxfiles : 'no limit') + '\r\n'; + } + if (typeof parent.config.settings.autobackup.googledrive == 'object') { + r += 'Google Drive Backups: Enabled\r\n'; + } + + } return r; } function buildSqlDumpCommand() { - var props = (obj.databaseType == 4) ? parent.args.mariadb : parent.args.mysql; + var props = (obj.databaseType == DB_MARIADB) ? parent.args.mariadb : parent.args.mysql; var mysqldumpPath = 'mysqldump'; if (parent.config.settings.autobackup && parent.config.settings.autobackup.mysqldumppath) { - mysqldumpPath = parent.config.settings.autobackup.mysqldumppath; + mysqldumpPath = path.normalize(parent.config.settings.autobackup.mysqldumppath); } var cmd = '\"' + mysqldumpPath + '\" --user=\'' + props.user + '\''; @@ -2681,11 +3287,11 @@ module.exports.CreateDB = function (parent, func) { // SSL options different on mariadb/mysql var sslOptions = ''; - if (obj.databaseType == 4) { + if (obj.databaseType == DB_MARIADB) { if (props.ssl) { sslOptions = ' --ssl'; if (props.ssl.cacertpath) sslOptions = ' --ssl-ca=' + props.ssl.cacertpath; - if (props.ssl.dontcheckserveridentity != true) sslOptions += ' --ssl-verify-server-cert'; + if (props.ssl.dontcheckserveridentity != true) {sslOptions += ' --ssl-verify-server-cert'} else {sslOptions += ' --ssl-verify-server-cert=false'}; if (props.ssl.clientcertpath) sslOptions += ' --ssl-cert=' + props.ssl.clientcertpath; if (props.ssl.clientkeypath) sslOptions += ' --ssl-key=' + props.ssl.clientkeypath; } @@ -2712,7 +3318,7 @@ module.exports.CreateDB = function (parent, func) { var mongoDumpPath = 'mongodump'; if (parent.config.settings.autobackup && parent.config.settings.autobackup.mongodumppath) { - mongoDumpPath = parent.config.settings.autobackup.mongodumppath; + mongoDumpPath = path.normalize(parent.config.settings.autobackup.mongodumppath); } var cmd = '"' + mongoDumpPath + '"'; @@ -2722,57 +3328,88 @@ module.exports.CreateDB = function (parent, func) { } // Check that the server is capable of performing a backup + // Tries configured custom location with fallback to default location + // Now runs after autobackup config init in meshcentral.js so config options are checked obj.checkBackupCapability = function (func) { - if ((parent.config.settings.autobackup == null) || (parent.config.settings.autobackup == false)) { func(); } - if ((obj.databaseType == 2) || (obj.databaseType == 3)) { - // Check that we have access to MongoDump - var backupPath = parent.backuppath; - if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; } - try { parent.fs.mkdirSync(backupPath); } catch (ex) { } - if (parent.fs.existsSync(backupPath) == false) { func(1, "Backup folder \"" + backupPath + "\" does not exist, database auto-backup will not be performed."); return; } + if ((parent.config.settings.autobackup == null) || (parent.config.settings.autobackup == false)) { return; }; + //block backup until validated. Gets put back if all checks are ok. + let backupInterval = parent.config.settings.autobackup.backupintervalhours; + parent.config.settings.autobackup.backupintervalhours = -1; + let backupPath = parent.backuppath; + if (backupPath.startsWith(parent.datapath)) { + func(1, "Backup path can't be set within meshcentral-data folder. No backups will be made."); + return; + } + // Check create/write backupdir + try { fs.mkdirSync(backupPath); } + catch (e) { + // EEXIST error = dir already exists + if (e.code != 'EEXIST' ) { + //Unable to create backuppath + console.error(e.message); + func(1, 'Unable to create ' + backupPath + '. No backups will be made. Error: ' + e.message); + return; + } + } + const testFile = path.join(backupPath, (parent.config.settings.autobackup.backupname + ".test")); + + try { fs.writeFileSync( testFile, "DeleteMe"); } + catch (e) { + //Unable to create file + console.error (e.message); + func(1, "Backuppath (" + backupPath + ") can't be written to. No backups will be made. Error: " + e.message); + return; + } + try { fs.unlinkSync(testFile); parent.debug('backup', 'Backuppath ' + backupPath + ' accesscheck successful');} + catch (e) { + console.error (e.message); + func(1, "Backuppathtestfile (" + testFile + ") can't be deleted, check filerights. Error: " + e.message); + // Assume write rights, no delete rights. Continue with warning. + //return; + } + + // Check database dumptools + if ((obj.databaseType == DB_MONGOJS) || (obj.databaseType == DB_MONGODB)) { + // Check that we have access to MongoDump var cmd = buildMongoDumpCommand(); cmd += (parent.platform == 'win32') ? ' --archive=\"nul\"' : ' --archive=\"/dev/null\"'; const child_process = require('child_process'); child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) { - try { - if ((error != null) && (error != '')) { - if (parent.platform == 'win32') { - func(1, "Unable to find mongodump.exe, MongoDB database auto-backup will not be performed."); - } else { - func(1, "Unable to find mongodump, MongoDB database auto-backup will not be performed."); - } - } else { - func(); - } - } catch (ex) { console.log(ex); } + if ((error != null) && (error != '')) { + func(1, "Unable to find mongodump tool, backup will not be performed. Command tried: " + cmd); + return; + } else {parent.config.settings.autobackup.backupintervalhours = backupInterval;} }); - } else if ((obj.databaseType == 4) || (obj.databaseType == 5)) { + } else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) { // Check that we have access to mysqldump - var backupPath = parent.backuppath; - if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; } - try { parent.fs.mkdirSync(backupPath); } catch (e) { } - if (parent.fs.existsSync(backupPath) == false) { func(1, "Backup folder \"" + backupPath + "\" does not exist, database auto-backup will not be performed."); return; } - var cmd = buildSqlDumpCommand(); cmd += ' > ' + ((parent.platform == 'win32') ? '\"nul\"' : '\"/dev/null\"'); const child_process = require('child_process'); - child_process.exec(cmd, { cwd: backupPath }, function(error, stdout, stdin) { - try { - if ((error != null) && (error != '')) { - if (parent.platform == 'win32') { - func(1, "Unable to find mysqldump.exe, MySQL/MariaDB database auto-backup will not be performed."); - } else { - func(1, "Unable to find mysqldump, MySQL/MariaDB database auto-backup will not be performed."); - } - } else { - func(); - } - } catch (ex) { console.log(ex); } + child_process.exec(cmd, { cwd: backupPath, timeout: 1000*30 }, function(error, stdout, stdin) { + if ((error != null) && (error != '')) { + func(1, "Unable to find mysqldump tool, backup will not be performed. Command tried: " + cmd); + return; + } else {parent.config.settings.autobackup.backupintervalhours = backupInterval;} + }); + } else if (obj.databaseType == DB_POSTGRESQL) { + // Check that we have access to pg_dump + parent.config.settings.autobackup.pgdumppath = path.normalize(parent.config.settings.autobackup.pgdumppath ? parent.config.settings.autobackup.pgdumppath : 'pg_dump'); + let cmd = '"' + parent.config.settings.autobackup.pgdumppath + '"' + + ' --dbname=postgresql://' + parent.config.settings.postgres.user + ":" +parent.config.settings.postgres.password + + "@" + parent.config.settings.postgres.host + ":" + parent.config.settings.postgres.port + "/" + databaseName + + ' > ' + ((parent.platform == 'win32') ? '\"nul\"' : '\"/dev/null\"'); + const child_process = require('child_process'); + child_process.exec(cmd, { cwd: backupPath }, function(error, stdout, stdin) { + if ((error != null) && (error != '')) { + func(1, "Unable to find pg_dump tool, backup will not be performed. Command tried: " + cmd); + return; + } else {parent.config.settings.autobackup.backupintervalhours = backupInterval;} + }); } else { - func(); - } + //all ok, enable backup + parent.config.settings.autobackup.backupintervalhours = backupInterval;} } // MongoDB pending bulk read operation, perform fast bulk document reads. @@ -2885,157 +3522,268 @@ module.exports.CreateDB = function (parent, func) { } // Perform a server backup - obj.performingBackup = false; obj.performBackup = function (func) { + parent.debug('backup','Entering performBackup'); try { - if (obj.performingBackup) return 1; + if (obj.performingBackup) return 'Backup alreay in progress.'; + if (parent.config.settings.autobackup.backupintervalhours == -1) { if (func) { func('Backup disabled.'); return 'Backup disabled.' }}; obj.performingBackup = true; - //console.log('Performing backup...'); + let backupPath = parent.backuppath; + let dataPath = parent.datapath; - var backupPath = parent.backuppath; - if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; } - try { parent.fs.mkdirSync(backupPath); } catch (e) { } - const dbname = (parent.args.mongodbname) ? (parent.args.mongodbname) : 'meshcentral'; - const dburl = parent.args.mongodb; const currentDate = new Date(); const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2); - const newAutoBackupFile = 'meshcentral-autobackup-' + fileSuffix; - const newAutoBackupPath = parent.path.join(backupPath, newAutoBackupFile); + obj.newAutoBackupFile = path.join(backupPath, parent.config.settings.autobackup.backupname + fileSuffix + '.zip'); + parent.debug('backup','newAutoBackupFile=' + obj.newAutoBackupFile); - if ((obj.databaseType == 2) || (obj.databaseType == 3)) { - // Perform a MongoDump backup - const newBackupFile = 'mongodump-' + fileSuffix; - var newBackupPath = parent.path.join(backupPath, newBackupFile); + if ((obj.databaseType == DB_MONGOJS) || (obj.databaseType == DB_MONGODB)) { + // Perform a MongoDump + const dbname = (parent.args.mongodbname) ? (parent.args.mongodbname) : 'meshcentral'; + const dburl = parent.args.mongodb; + + obj.newDBDumpFile = path.join(backupPath, (dbname + '-mongodump-' + fileSuffix + '.archive')); var cmd = buildMongoDumpCommand(); - cmd += (dburl) ? ' --archive=\"' + newBackupPath + '.archive\"' : - ' --db=\"' + dbname + '\" --archive=\"' + newBackupPath + '.archive\"'; - + cmd += (dburl) ? ' --archive=\"' + obj.newDBDumpFile + '\"' : + ' --db=\"' + dbname + '\" --archive=\"' + obj.newDBDumpFile + '\"'; + parent.debug('backup','Mongodump cmd: ' + cmd); const child_process = require('child_process'); - var backupProcess = child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) { - try { - var mongoDumpSuccess = true; - backupProcess = null; - if ((error != null) && (error != '')) { mongoDumpSuccess = false; console.log('ERROR: Unable to perform MongoDB backup: ' + error + '\r\n'); } + const dumpProcess = child_process.exec( + cmd, + { cwd: parent.parentpath }, + (error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.error('ERROR: Unable to perform MongoDB backup: ' + error + '\r\n'); obj.createBackupfile(func);}} + ); + + dumpProcess.on('exit', (code) => { + if (code != 0) {console.log(`Mongodump child process exited with code ${code}`); obj.backupStatus |= BACKUPFAIL_DBDUMP;} + obj.createBackupfile(func); + }); - // Perform archive compression - var archiver = require('archiver'); - var output = parent.fs.createWriteStream(newAutoBackupPath + '.zip'); - var archive = null; - if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { - try { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } catch (ex) { } - archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); - } else { - archive = archiver('zip', { zlib: { level: 9 } }); - } - output.on('close', function () { - obj.performingBackup = false; - if (func) { if (mongoDumpSuccess) { func('Auto-backup completed.'); } else { func('Auto-backup completed without mongodb database: ' + error); } } - obj.performCloudBackup(newAutoBackupPath + '.zip', func); - setTimeout(function () { try { parent.fs.unlink(newBackupPath + '.archive', function () { }); } catch (ex) { console.log(ex); } }, 5000); - }); - output.on('end', function () { }); - output.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } }); - archive.on('warning', function (err) { console.log('Backup warning: ' + err); if (func) { func('Backup warning: ' + err); } }); - archive.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } }); - archive.pipe(output); - if (mongoDumpSuccess == true) { archive.file(newBackupPath + '.archive', { name: newBackupFile + '.archive' }); } - archive.directory(parent.datapath, 'meshcentral-data'); - archive.finalize(); - } catch (ex) { console.log(ex); } - }); - } else if ((obj.databaseType == 4) || (obj.databaseType == 5)) { + } else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) { // Perform a MySqlDump backup const newBackupFile = 'mysqldump-' + fileSuffix; - var newBackupPath = parent.path.join(backupPath, newBackupFile); + obj.newDBDumpFile = path.join(backupPath, newBackupFile + '.sql'); var cmd = buildSqlDumpCommand(); - cmd += ' --result-file=\"' + newBackupPath + '.sql\"'; - const child_process = require('child_process'); - var backupProcess = child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) { - try { - var sqlDumpSuccess = true; - backupProcess = null; - if ((error != null) && (error != '')) { sqlDumpSuccess = false; console.log('ERROR: Unable to perform MySQL/MariaDB backup: ' + error + '\r\n'); } + cmd += ' --result-file=\"' + obj.newDBDumpFile + '\"'; + parent.debug('backup','Maria/MySQLdump cmd: ' + cmd); - var archiver = require('archiver'); - var output = parent.fs.createWriteStream(newAutoBackupPath + '.zip'); - var archive = null; - if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { - try { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } catch (ex) { } - archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); - } else { - archive = archiver('zip', { zlib: { level: 9 } }); - } - output.on('close', function () { - obj.performingBackup = false; - if (func) { if (sqlDumpSuccess) { func('Auto-backup completed.'); } else { func('Auto-backup completed without MySQL/MariaDB database: ' + error); } } - obj.performCloudBackup(newAutoBackupPath + '.zip', func); - setTimeout(function () { try { parent.fs.unlink(newBackupPath + '.sql', function () { }); } catch (ex) { console.log(ex); } }, 5000); - }); - output.on('end', function () { }); - output.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } }); - archive.on('warning', function (err) { console.log('Backup warning: ' + err); if (func) { func('Backup warning: ' + err); } }); - archive.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } }); - archive.pipe(output); - if (sqlDumpSuccess == true) { archive.file(newBackupPath + '.sql', { name: newBackupFile + '.sql' }); } - archive.directory(parent.datapath, 'meshcentral-data'); - archive.finalize(); - } catch (ex) { console.log(ex); } + const child_process = require('child_process'); + const dumpProcess = child_process.exec( + cmd, + { cwd: parent.parentpath }, + (error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.error('ERROR: Unable to perform MySQL backup: ' + error + '\r\n'); obj.createBackupfile(func);}} + ); + dumpProcess.on('exit', (code) => { + if (code != 0) {console.error(`MySQLdump child process exited with code ${code}`); obj.backupStatus |= BACKUPFAIL_DBDUMP;} + obj.createBackupfile(func); + }); + + } else if (obj.databaseType == DB_SQLITE) { + //.db3 suffix to escape escape backupfile glob to exclude the sqlite db files + obj.newDBDumpFile = path.join(backupPath, databaseName + '-sqlitedump-' + fileSuffix + '.db3'); + // do a VACUUM INTO in favor of the backup API to compress the export, see https://www.sqlite.org/backup.html + parent.debug('backup','SQLitedump: VACUUM INTO ' + obj.newDBDumpFile); + obj.file.exec('VACUUM INTO \'' + obj.newDBDumpFile + '\'', function (err) { + if (err) { console.error('SQLite backup error: ' + err); obj.backupStatus |=BACKUPFAIL_DBDUMP;}; + //always finish/clean up + obj.createBackupfile(func); + }); + } else if (obj.databaseType == DB_POSTGRESQL) { + // Perform a PostgresDump backup + const newBackupFile = databaseName + '-pgdump-' + fileSuffix + '.sql'; + obj.newDBDumpFile = path.join(backupPath, newBackupFile); + let cmd = '"' + parent.config.settings.autobackup.pgdumppath + '"' + + ' --dbname=postgresql://' + parent.config.settings.postgres.user + ":" +parent.config.settings.postgres.password + + "@" + parent.config.settings.postgres.host + ":" + parent.config.settings.postgres.port + "/" + databaseName + + " --file=" + obj.newDBDumpFile; + parent.debug('backup','Postgresqldump cmd: ' + cmd); + const child_process = require('child_process'); + const dumpProcess = child_process.exec( + cmd, + { cwd: dataPath }, + (error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.log('ERROR: Unable to perform PostgreSQL dump: ' + error.message + '\r\n'); obj.createBackupfile(func);}} + ); + dumpProcess.on('exit', (code) => { + if (code != 0) {console.log(`PostgreSQLdump child process exited with code: ` + code); obj.backupStatus |= BACKUPFAIL_DBDUMP;} + obj.createBackupfile(func); }); } else { - // Perform a NeDB backup - var archiver = require('archiver'); - var output = parent.fs.createWriteStream(newAutoBackupPath + '.zip'); - var archive = null; - if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { - try { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } catch (ex) { } - archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); - } else { - archive = archiver('zip', { zlib: { level: 9 } }); - } - output.on('close', function () { obj.performingBackup = false; if (func) { func('Auto-backup completed.'); } obj.performCloudBackup(newAutoBackupPath + '.zip', func); }); - output.on('end', function () { }); - output.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } }); - archive.on('warning', function (err) { console.log('Backup warning: ' + err); if (func) { func('Backup warning: ' + err); } }); - archive.on('error', function (err) { console.log('Backup error: ' + err); if (func) { func('Backup error: ' + err); } }); - archive.pipe(output); - archive.directory(parent.datapath, 'meshcentral-data'); - archive.finalize(); + // NeDB/Acebase backup, no db dump needed, just make a file backup + obj.createBackupfile(func); } + } catch (ex) { console.error(ex); parent.addServerWarning( 'Something went wrong during performBackup, check errorlog: ' +ex.message, true); }; + return 'Starting auto-backup...'; + }; - // Remove old backups - if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.keeplastdaysbackup == 'number')) { - var cutoffDate = new Date(); - cutoffDate.setDate(cutoffDate.getDate() - parent.config.settings.autobackup.keeplastdaysbackup); - parent.fs.readdir(parent.backuppath, function (err, dir) { - try { - if ((err == null) && (dir.length > 0)) { + obj.createBackupfile = function(func) { + parent.debug('backup', 'Entering createBackupfile'); + let archiver = require('archiver'); + let archive = null; + let zipLevel = Math.min(Math.max(Number(parent.config.settings.autobackup.zipcompression ? parent.config.settings.autobackup.zipcompression : 5),1),9); + + //if password defined, create encrypted zip + if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.zippassword == 'string')) { + try { + //Only register format once, otherwise it triggers an error + if (archiver.isRegisteredFormat('zip-encrypted') == false) { archiver.registerFormat('zip-encrypted', require('archiver-zip-encrypted')); } + archive = archiver.create('zip-encrypted', { zlib: { level: zipLevel }, encryptionMethod: 'aes256', password: parent.config.settings.autobackup.zippassword }); + if (func) { func('Creating encrypted ZIP'); } + } catch (ex) { // registering encryption failed, do not fall back to non-encrypted, fail backup and skip old backup removal as a precaution to not lose any backups + obj.backupStatus |= BACKUPFAIL_ZIPMODULE; + if (func) { func('Zipencryptionmodule failed, aborting');} + console.error('Zipencryptionmodule failed, aborting'); + } + } else { + if (func) { func('Creating a NON-ENCRYPTED ZIP'); } + archive = archiver('zip', { zlib: { level: zipLevel } }); + } + + //original behavior, just a filebackup if dbdump fails : (obj.backupStatus == 0 || obj.backupStatus == BACKUPFAIL_DBDUMP) + if (obj.backupStatus == 0) { + // Zip the data directory with the dbdump|NeDB files + let output = fs.createWriteStream(obj.newAutoBackupFile); + + // Archive finalized and closed + output.on('close', function () { + if (obj.backupStatus == 0) { + let mesg = 'Auto-backup completed: ' + obj.newAutoBackupFile + ', backup-size: ' + ((archive.pointer() / 1048576).toFixed(2)) + "Mb"; + console.log(mesg); + if (func) { func(mesg); }; + obj.performCloudBackup(obj.newAutoBackupFile, func); + obj.removeExpiredBackupfiles(func); + + } else { + let mesg = 'Zipbackup failed (' + obj.backupStatus.toString(2).slice(-8) + '), deleting incomplete backup: ' + obj.newAutoBackupFile; + if (func) { func(mesg) } + else { parent.addServerWarning(mesg, true ) }; + if (fs.existsSync(obj.newAutoBackupFile)) { fs.unlink(obj.newAutoBackupFile, function (err) { console.error('Failed to clean up backupfile: ' + err.message) }) }; + }; + if (obj.databaseType != DB_NEDB) { + //remove dump archive file, because zipped and otherwise fills up + if (fs.existsSync(obj.newDBDumpFile)) { fs.unlink(obj.newDBDumpFile, function (err) { if (err) {console.error('Failed to clean up dbdump file: ' + err.message) } }) }; + }; + obj.performingBackup = false; + obj.backupStatus = 0x0; + } + ); + output.on('end', function () { }); + output.on('error', function (err) { + if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) { + console.error('Output error: ' + err.message); + if (func) { func('Output error: ' + err.message); }; + obj.backupStatus |= BACKUPFAIL_ZIPCREATE; + archive.abort(); + }; + }); + archive.on('warning', function (err) { + //if files added to the archiver object aren't reachable anymore (e.g. sqlite-journal files) + //an ENOENT warning is given, but the archiver module has no option to/does not skip/resume + //so the backup needs te be aborted as it otherwise leaves an incomplete zip and never 'ends' + if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) { + console.log('Zip warning: ' + err.message); + if (func) { func('Zip warning: ' + err.message); }; + obj.backupStatus |= BACKUPFAIL_ZIPCREATE; + archive.abort(); + }; + }); + archive.on('error', function (err) { + if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) { + console.error('Zip error: ' + err.message); + if (func) { func('Zip error: ' + err.message); }; + obj.backupStatus |= BACKUPFAIL_ZIPCREATE; + archive.abort(); + } + }); + archive.pipe(output); + + let globIgnoreFiles; + //slice in case exclusion gets pushed + globIgnoreFiles = parent.config.settings.autobackup.backupignorefilesglob ? parent.config.settings.autobackup.backupignorefilesglob.slice() : []; + if (parent.config.settings.sqlite3) { globIgnoreFiles.push (datapathFoldername + '/' + databaseName + '.sqlite*'); }; //skip sqlite database file, and temp files with ext -journal, -wal & -shm + //archiver.glob doesn't seem to use the third param, archivesubdir. Bug? + //workaround: go up a dir and add data dir explicitly to keep the zip tidy + archive.glob((datapathFoldername + '/**'), { + cwd: datapathParentPath, + ignore: globIgnoreFiles, + skip: (parent.config.settings.autobackup.backupskipfoldersglob ? parent.config.settings.autobackup.backupskipfoldersglob : []) + }); + + if (parent.config.settings.autobackup.backupwebfolders) { + if (parent.webViewsOverridePath) { archive.directory(parent.webViewsOverridePath, 'meshcentral-views'); } + if (parent.webPublicOverridePath) { archive.directory(parent.webPublicOverridePath, 'meshcentral-public'); } + if (parent.webEmailsOverridePath) { archive.directory(parent.webEmailsOverridePath, 'meshcentral-emails'); } + }; + if (parent.config.settings.autobackup.backupotherfolders) { + archive.directory(parent.filespath, 'meshcentral-files'); + archive.directory(parent.recordpath, 'meshcentral-recordings'); + }; + //add dbdump to the root of the zip + if (obj.newDBDumpFile != null) archive.file(obj.newDBDumpFile, { name: path.basename(obj.newDBDumpFile) }); + archive.finalize(); + } else { + //failed somewhere before zipping + console.error('Backup failed ('+ obj.backupStatus.toString(2).slice(-8) + ')'); + if (func) { func('Backup failed ('+ obj.backupStatus.toString(2).slice(-8) + ')') } + else { + parent.addServerWarning('Backup failed ('+ obj.backupStatus.toString(2).slice(-8) + ')', true); + } + //Just in case something's there + if (fs.existsSync(obj.newDBDumpFile)) { fs.unlink(obj.newDBDumpFile, function (err) { if (err) {console.error('Failed to clean up dbdump file: ' + err.message) } }); }; + obj.backupStatus = 0x0; + obj.performingBackup = false; + }; + }; + + // Remove expired backupfiles by filenamedate + obj.removeExpiredBackupfiles = function (func) { + if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.keeplastdaysbackup == 'number')) { + let cutoffDate = new Date(); + cutoffDate.setDate(cutoffDate.getDate() - parent.config.settings.autobackup.keeplastdaysbackup); + fs.readdir(parent.backuppath, function (err, dir) { + try { + if (err == null) { + if (dir.length > 0) { + let fileName = parent.config.settings.autobackup.backupname; + let checked = 0; + let removed = 0; for (var i in dir) { var name = dir[i]; - if (name.startsWith('meshcentral-autobackup-') && name.endsWith('.zip')) { - var timex = name.substring(23, name.length - 4).split('-'); + parent.debug('backup', "checking file: ", path.join(parent.backuppath, name)); + if (name.startsWith(fileName) && name.endsWith('.zip')) { + var timex = name.substring(fileName.length, name.length - 4).split('-'); if (timex.length == 5) { + checked++; var fileDate = new Date(parseInt(timex[0]), parseInt(timex[1]) - 1, parseInt(timex[2]), parseInt(timex[3]), parseInt(timex[4])); - if (fileDate && (cutoffDate > fileDate)) { try { parent.fs.unlink(parent.path.join(parent.backuppath, name), function () { }); } catch (ex) { } } + if (fileDate && (cutoffDate > fileDate)) { + console.log("Removing expired backup file: ", path.join(parent.backuppath, name)); + fs.unlink(path.join(parent.backuppath, name), function (err) { if (err) { console.error(err.message); if (func) {func('Error removing: ' + err.message); } } }); + removed++; + } } + else { parent.debug('backup', "file: " + name + " timestamp failure: ", timex); } } } - } - } catch (ex) { console.log(ex); } - }); - } - } catch (ex) { console.log(ex); } - return 0; + let mesg= 'Checked ' + checked + ' candidates in ' + parent.backuppath + '. Removed ' + removed + ' expired backupfiles using cutoffDate: '+ cutoffDate.toLocaleString('default', { dateStyle: 'short', timeStyle: 'short' }); + parent.debug (mesg); + if (func) { func(mesg); } + } else { console.error('No files found in ' + parent.backuppath + '. There should be at least one.')} + } + else + { console.error(err); parent.addServerWarning( 'Reading files in backup directory ' + parent.backuppath + ' failed, check errorlog: ' + err.message, true); } + } catch (ex) { console.error(ex); parent.addServerWarning( 'Something went wrong during removeExpiredBackupfiles, check errorlog: ' +ex.message, true); } + }); + } } // Perform cloud backup obj.performCloudBackup = function (filename, func) { - // WebDAV Backup if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.webdav == 'object')) { - const xdateTimeSort = function (a, b) { if (a.xdate > b.xdate) return 1; if (a.xdate < b.xdate) return -1; return 0; } + parent.debug( 'backup', 'Entering WebDAV backup'); + if (func) { func('Entering WebDAV backup.'); } + const xdateTimeSort = function (a, b) { if (a.xdate > b.xdate) return 1; if (a.xdate < b.xdate) return -1; return 0; } // Fetch the folder name var webdavfolderName = 'MeshCentral-Backups'; if (typeof parent.config.settings.autobackup.webdav.foldername == 'string') { webdavfolderName = parent.config.settings.autobackup.webdav.foldername; } @@ -3043,65 +3791,74 @@ module.exports.CreateDB = function (parent, func) { // Clean up our WebDAV folder function performWebDavCleanup(client) { if ((typeof parent.config.settings.autobackup.webdav.maxfiles == 'number') && (parent.config.settings.autobackup.webdav.maxfiles > 1)) { - var directoryItems = client.getDirectoryContents(webdavfolderName); + let fileName = parent.config.settings.autobackup.backupname; + //only files matching our backupfilename + let directoryItems = client.getDirectoryContents(webdavfolderName, { deep: false, glob: "/**/" + fileName + "*.zip" }); directoryItems.then( function (files) { for (var i in files) { files[i].xdate = new Date(files[i].lastmod); } files.sort(xdateTimeSort); + parent.debug('backup','WebDAV filtered directory contents: ' + JSON.stringify(files, null, 4)); while (files.length >= parent.config.settings.autobackup.webdav.maxfiles) { - client.deleteFile(files.shift().filename).then(function (state) { - if (func) { func('WebDAV file deleted.'); } + let delFile = files.shift().filename; + client.deleteFile(delFile).then(function (state) { + parent.debug('backup','WebDAV file deleted: ' + delFile); + if (func) { func('WebDAV file deleted: ' + delFile); } }).catch(function (err) { - if (func) { func('WebDAV (deleteFile) error: ' + err); } + console.error(err); + if (func) { func('WebDAV (deleteFile) error: ' + err.message); } }); } } ).catch(function (err) { - if (func) { func('WebDAV (getDirectoryContents) error: ' + err); } + console.error(err); + if (func) { func('WebDAV (getDirectoryContents) error: ' + err.message); } }); } } // Upload to the WebDAV folder function performWebDavUpload(client, filepath) { - var fileStream = require('fs').createReadStream(filepath); - fileStream.on('close', function () { if (func) { func('WebDAV upload completed'); } }) - fileStream.on('error', function (err) { if (func) { func('WebDAV (fileUpload) error: ' + err); } }) - fileStream.pipe(client.createWriteStream('/' + webdavfolderName + '/' + require('path').basename(filepath))); - if (func) { func('Uploading using WebDAV...'); } + require('fs').stat(filepath, function(err,stat){ + var fileStream = require('fs').createReadStream(filepath); + fileStream.on('close', function () { console.log('WebDAV upload completed: ' + webdavfolderName + '/' + require('path').basename(filepath)); if (func) { func('WebDAV upload completed: ' + webdavfolderName + '/' + require('path').basename(filepath)); } }) + fileStream.on('error', function (err) { console.error(err); if (func) { func('WebDAV (fileUpload) error: ' + err.message); } }) + fileStream.pipe(client.createWriteStream('/' + webdavfolderName + '/' + require('path').basename(filepath), { headers: { "Content-Length": stat.size } })); + parent.debug('backup', 'Uploading using WebDAV to: ' + parent.config.settings.autobackup.webdav.url); + if (func) { func('Uploading using WebDAV to: ' + parent.config.settings.autobackup.webdav.url); } + }); } - if (func) { func('Attempting WebDAV upload...'); } const { createClient } = require('webdav'); - const client = createClient(parent.config.settings.autobackup.webdav.url, { username: parent.config.settings.autobackup.webdav.username, password: parent.config.settings.autobackup.webdav.password }); - var directoryItems = client.getDirectoryContents('/'); - directoryItems.then( - function (files) { - var folderFound = false; - for (var i in files) { if ((files[i].basename == webdavfolderName) && (files[i].type == 'directory')) { folderFound = true; } } - if (folderFound == false) { - client.createDirectory(webdavfolderName).then(function (a) { - if (a.statusText == 'Created') { - if (func) { func('WebDAV folder created'); } - performWebDavUpload(client, filename); - } else { - if (func) { func('WebDAV (createDirectory) status: ' + a.statusText); } - } - }).catch(function (err) { - if (func) { func('WebDAV (createDirectory) error: ' + err); } - }); - } else { - performWebDavCleanup(client); + const client = createClient(parent.config.settings.autobackup.webdav.url, { + username: parent.config.settings.autobackup.webdav.username, + password: parent.config.settings.autobackup.webdav.password, + maxContentLength: Infinity, + maxBodyLength: Infinity + }); + client.exists(webdavfolderName).then(function(a){ + if(a){ + performWebDavCleanup(client); + performWebDavUpload(client, filename); + }else{ + client.createDirectory(webdavfolderName, {recursive: true}).then(function (a) { + console.log('backup','WebDAV folder created: ' + webdavfolderName); + if (func) { func('WebDAV folder created: ' + webdavfolderName); } performWebDavUpload(client, filename); - } + }).catch(function (err) { + console.error(err); + if (func) { func('WebDAV (createDirectory) error: ' + err.message); } + }); } - ).catch(function (err) { - if (func) { func('WebDAV (getDirectoryContents) error: ' + err); } + }).catch(function (err) { + console.error(err); + if (func) { func('WebDAV (exists) error: ' + err.message); } }); } // Google Drive Backup if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.googledrive == 'object')) { + parent.debug( 'backup', 'Entering Google Drive backup'); obj.Get('GoogleDriveBackup', function (err, docs) { if ((err != null) || (docs.length != 1) || (docs[0].state != 3)) return; if (func) { func('Attempting Google Drive upload...'); } @@ -3177,11 +3934,111 @@ module.exports.CreateDB = function (parent, func) { }); }); } + + // S3 Backup + if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.s3 == 'object')) { + parent.debug( 'backup', 'Entering S3 backup'); + var s3folderName = 'MeshCentral-Backups'; + if (typeof parent.config.settings.autobackup.s3.foldername == 'string') { s3folderName = parent.config.settings.autobackup.s3.foldername; } + // Construct the config object + var accessKey = parent.config.settings.autobackup.s3.accesskey, + secretKey = parent.config.settings.autobackup.s3.secretkey, + endpoint = parent.config.settings.autobackup.s3.endpoint ? parent.config.settings.autobackup.s3.endpoint : 's3.amazonaws.com', + port = parent.config.settings.autobackup.s3.port ? parent.config.settings.autobackup.s3.port : 443, + useSsl = parent.config.settings.autobackup.s3.ssl ? parent.config.settings.autobackup.s3.ssl : true, + bucketName = parent.config.settings.autobackup.s3.bucketname, + pathPrefix = s3folderName, + threshold = parent.config.settings.autobackup.s3.maxfiles ? parent.config.settings.autobackup.s3.maxfiles : 0, + fileToUpload = filename; + // Create a MinIO client + const Minio = require('minio'); + var minioClient = new Minio.Client({ + endPoint: endpoint, + port: port, + useSSL: useSsl, + accessKey: accessKey, + secretKey: secretKey + }); + // List objects in the specified bucket and path prefix + var listObjectsPromise = new Promise(function(resolve, reject) { + var items = []; + var stream = minioClient.listObjects(bucketName, pathPrefix, true); + stream.on('data', function(item) { + if (!item.name.endsWith('/')) { // Exclude directories + items.push(item); + } + }); + stream.on('end', function() { + resolve(items); + }); + stream.on('error', function(err) { + reject(err); + }); + }); + listObjectsPromise.then(function(objects) { + // Count the number of files + var fileCount = objects.length; + // Return if no files to carry on uploading + if (fileCount === 0) { return Promise.resolve(); } + // Sort the files by LastModified date (oldest first) + objects.sort(function(a, b) { return new Date(a.lastModified) - new Date(b.lastModified); }); + // Check if the threshold is zero and return if + if (threshold === 0) { return Promise.resolve(); } + // Check if the number of files exceeds the threshold (maxfiles) is 0 + if (fileCount >= threshold) { + // Calculate how many files need to be deleted to make space for the new file + var filesToDelete = fileCount - threshold + 1; // +1 to make space for the new file + if (func) { func('Deleting ' + filesToDelete + ' older ' + (filesToDelete == 1 ? 'file' : 'files') + ' from S3 ...'); } + // Create an array of promises for deleting files + var deletePromises = objects.slice(0, filesToDelete).map(function(fileToDelete) { + return new Promise(function(resolve, reject) { + minioClient.removeObject(bucketName, fileToDelete.name, function(err) { + if (err) { + reject(err); + } else { + if (func) { func('Deleted file: ' + fileToDelete.name + ' from S3'); } + resolve(); + } + }); + }); + }); + // Wait for all deletions to complete + return Promise.all(deletePromises); + } else { + return Promise.resolve(); // No deletion needed + } + }).then(function() { + // Determine the upload path by combining the pathPrefix with the filename + var fileName = require('path').basename(fileToUpload); + var uploadPath = require('path').join(pathPrefix, fileName); + // Upload a new file + var uploadPromise = new Promise(function(resolve, reject) { + if (func) { func('Uploading file ' + uploadPath + ' to S3'); } + minioClient.fPutObject(bucketName, uploadPath, fileToUpload, function(err, etag) { + if (err) { + reject(err); + } else { + if (func) { func('Uploaded file: ' + uploadPath + ' to S3'); } + resolve(etag); + } + }); + }); + return uploadPromise; + }).catch(function(error) { + if (func) { func('Error managing files in S3: ' + error); } + }); + } } // Transfer NeDB data into the current database obj.nedbtodb = function (func) { - var nedbDatastore = require('nedb'); + var nedbDatastore = null; + try { nedbDatastore = require('@seald-io/nedb'); } catch (ex) { } // This is the NeDB with Node 23 support. + if (nedbDatastore == null) { + try { nedbDatastore = require('@yetzt/nedb'); } catch (ex) { } // This is the NeDB with fixed security dependencies. + if (nedbDatastore == null) { nedbDatastore = require('nedb'); } // So not to break any existing installations, if the old NeDB is present, use it. + } + var datastoreOptions = { filename: parent.getConfigFilePath('meshcentral.db'), autoload: true }; // If a DB encryption key is provided, perform database encryption @@ -3217,16 +4074,16 @@ module.exports.CreateDB = function (parent, func) { var eventRecordsTransferCount = 0; var powerRecordsTransferCount = 0; var statsRecordsTransferCount = 0; - var pendingTransfer = 0; + obj.pendingTransfer = 0; // Transfer the data from main database nedbfile.find({}, function (err, docs) { if ((err == null) && (docs.length > 0)) { performTypedRecordDecrypt(docs) for (var i in docs) { - pendingTransfer++; + obj.pendingTransfer++; normalRecordsTransferCount++; - obj.Set(common.unEscapeLinksFieldName(docs[i]), function () { pendingTransfer--; }); + obj.Set(common.unEscapeLinksFieldName(docs[i]), function () { obj.pendingTransfer--; }); } } @@ -3234,9 +4091,9 @@ module.exports.CreateDB = function (parent, func) { nedbeventsfile.find({}, function (err, docs) { if ((err == null) && (docs.length > 0)) { for (var i in docs) { - pendingTransfer++; + obj.pendingTransfer++; eventRecordsTransferCount++; - obj.StoreEvent(docs[i], function () { pendingTransfer--; }); + obj.StoreEvent(docs[i], function () { obj.pendingTransfer--; }); } } @@ -3244,9 +4101,9 @@ module.exports.CreateDB = function (parent, func) { nedbpowerfile.find({}, function (err, docs) { if ((err == null) && (docs.length > 0)) { for (var i in docs) { - pendingTransfer++; + obj.pendingTransfer++; powerRecordsTransferCount++; - obj.storePowerEvent(docs[i], null, function () { pendingTransfer--; }); + obj.storePowerEvent(docs[i], null, function () { obj.pendingTransfer--; }); } } @@ -3254,15 +4111,15 @@ module.exports.CreateDB = function (parent, func) { nedbserverstatsfile.find({}, function (err, docs) { if ((err == null) && (docs.length > 0)) { for (var i in docs) { - pendingTransfer++; + obj.pendingTransfer++; statsRecordsTransferCount++; - obj.SetServerStats(docs[i], function () { pendingTransfer--; }); + obj.SetServerStats(docs[i], function () { obj.pendingTransfer--; }); } } // Only exit when all the records are stored. setInterval(function () { - if (pendingTransfer == 0) { func("Done. " + normalRecordsTransferCount + " record(s), " + eventRecordsTransferCount + " event(s), " + powerRecordsTransferCount + " power change(s), " + statsRecordsTransferCount + " stat(s)."); } + if (obj.pendingTransfer == 0) { func("Done. " + normalRecordsTransferCount + " record(s), " + eventRecordsTransferCount + " event(s), " + powerRecordsTransferCount + " power change(s), " + statsRecordsTransferCount + " stat(s)."); } }, 200) }); }); @@ -3274,6 +4131,7 @@ module.exports.CreateDB = function (parent, func) { // Called when a node has changed function dbNodeChange(nodeChange, added) { + if (parent.webserver == null) return; common.unEscapeLinksFieldName(nodeChange.fullDocument); const node = performTypedRecordDecrypt([nodeChange.fullDocument])[0]; parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: (added ? 'addnode' : 'changenode'), node: parent.webserver.CloneSafeNode(node), nodeid: node._id, domain: node.domain, nolog: 1 }); @@ -3297,12 +4155,13 @@ module.exports.CreateDB = function (parent, func) { } // Send the mesh update - if (mesh.deleted) { mesh.action = 'deletemesh'; } else { mesh.action = (added ? 'createmesh' : 'meshchange'); } - mesh.meshid = mesh._id; - mesh.nolog = 1; - delete mesh.type; - delete mesh._id; - parent.DispatchEvent(['*', mesh.meshid], obj, parent.webserver.CloneSafeMesh(mesh)); + var mesh2 = Object.assign({}, mesh); // Shallow clone + if (mesh2.deleted) { mesh2.action = 'deletemesh'; } else { mesh2.action = (added ? 'createmesh' : 'meshchange'); } + mesh2.meshid = mesh2._id; + mesh2.nolog = 1; + delete mesh2.type; + delete mesh2._id; + parent.DispatchEvent(['*', mesh2.meshid], obj, parent.webserver.CloneSafeMesh(mesh2)); } // Called when a user account has changed @@ -3346,17 +4205,18 @@ module.exports.CreateDB = function (parent, func) { } // Send the user group update - usergroup.action = (added ? 'createusergroup' : 'usergroupchange'); - usergroup.ugrpid = usergroup._id; - usergroup.nolog = 1; - delete usergroup.type; - delete usergroup._id; - parent.DispatchEvent(['*', usergroup.ugrpid], obj, usergroup); + var usergroup2 = Object.assign({}, usergroup); // Shallow clone + usergroup2.action = (added ? 'createusergroup' : 'usergroupchange'); + usergroup2.ugrpid = usergroup2._id; + usergroup2.nolog = 1; + delete usergroup2.type; + delete usergroup2._id; + parent.DispatchEvent(['*', usergroup2.ugrpid], obj, usergroup2); } function dbMergeSqlArray(arr) { var x = ''; - for (var i in arr) { if (x != '') { x += ','; } x += '"' + arr[i] + '"'; } + for (var i in arr) { if (x != '') { x += ','; } x += '\'' + arr[i] + '\''; } return x; } diff --git a/dependencies.txt b/dependencies.txt index 5a3021e9..6bf8bcdd 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -1,15 +1,16 @@ - "archiver": "^5.3.1", - "body-parser": "^1.19.0", - "cbor": "~5.2.0", - "compression": "^1.7.4", - "cookie-session": "^1.4.0", - "express": "^4.17.0", - "express-handlebars": "^5.3.5", - "express-ws": "^4.0.0", - "ipcheck": "^0.1.0", - "minimist": "^1.2.5", - "multiparty": "^4.2.1", - "@yetzt/nedb": "^1.8.0", - "node-forge": "^1.0.0", - "ws": "^5.2.3", - "yauzl": "^2.10.0" \ No newline at end of file + "@seald-io/nedb": "4.0.4", + "archiver": "7.0.1", + "body-parser": "1.20.3", + "cbor": "5.2.0", + "compression": "1.7.5", + "cookie-session": "2.1.0", + "express": "4.21.2", + "express-handlebars": "7.1.3", + "express-ws": "5.0.2", + "ipcheck": "0.1.0", + "minimist": "1.2.8", + "multiparty": "4.2.3", + "node-forge": "1.3.1", + "ua-parser-js": "1.0.39", + "ws": "8.18.0", + "yauzl": "2.10.0" \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 377ce6b2..26806e1d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,35 +1,24 @@ -FROM alpine:latest AS base +FROM --platform=$BUILDPLATFORM node:22-alpine AS builder -#Add non-root user, add installation directories and assign proper permissions RUN mkdir -p /opt/meshcentral/meshcentral - -# meshcentral installation +COPY ./ /opt/meshcentral/meshcentral/ WORKDIR /opt/meshcentral -RUN apk update \ - && apk add --no-cache --update tzdata nodejs npm bash \ - && rm -rf /var/cache/apk/* -RUN npm install -g npm@latest - - -FROM base AS builder - ARG DISABLE_MINIFY="" ARG DISABLE_TRANSLATE="" -COPY ./ /opt/meshcentral/meshcentral/ RUN if ! [ -z "$DISABLE_MINIFY" ] && [ "$DISABLE_MINIFY" != "yes" ] && [ "$DISABLE_MINIFY" != "YES" ] \ && [ "$DISABLE_MINIFY" != "true" ] && [ "$DISABLE_MINIFY" != "TRUE" ]; then \ - echo -e "\e[0;31;49mInvalid value for build argument DISABLE_MINIFY, possible values: yes/true\e[;0m"; exit 1; \ + echo -e "\e[0;31;49mInvalid value for build argument DISABLE_MINIFY, possible values: yes/true\e[;0m"; exit 1; \ fi RUN if ! [ -z "$DISABLE_TRANSLATE" ] && [ "$DISABLE_TRANSLATE" != "yes" ] && [ "$DISABLE_TRANSLATE" != "YES" ] \ && [ "$DISABLE_TRANSLATE" != "true" ] && [ "$DISABLE_TRANSLATE" != "TRUE" ]; then \ - echo -e "\e[0;31;49mInvalid value for build argument DISABLE_TRANSLATE, possible values: yes/true\e[;0m"; exit 1; \ + echo -e "\e[0;31;49mInvalid value for build argument DISABLE_TRANSLATE, possible values: yes/true\e[;0m"; exit 1; \ fi # install translate/minify modules if need too -RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral && npm install html-minifier jsdom minify-js; fi +RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral && npm install html-minifier@4.0.0 jsdom@22.1.0 esprima@4.0.1; fi # first extractall if need too RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js extractall; fi @@ -45,7 +34,18 @@ RUN rm -rf /opt/meshcentral/meshcentral/docker RUN rm -rf /opt/meshcentral/meshcentral/node_modules -FROM base +FROM --platform=$TARGETPLATFORM alpine:3.21 + +#Add non-root user, add installation directories and assign proper permissions +RUN mkdir -p /opt/meshcentral/meshcentral + +# meshcentral installation +WORKDIR /opt/meshcentral + +RUN apk update \ + && apk add --no-cache --update tzdata nodejs npm bash python3 make gcc g++ \ + && rm -rf /var/cache/apk/* +RUN npm install -g npm@latest ARG INCLUDE_MONGODBTOOLS="" ARG PREINSTALL_LIBS="false" @@ -58,20 +58,22 @@ ENV CONFIG_FILE="config.json" ENV USE_MONGODB="false" ENV MONGO_INITDB_ROOT_USERNAME="root" ENV MONGO_INITDB_ROOT_PASSWORD="pass" +ENV MONGO_URL="" ENV HOSTNAME="localhost" ENV ALLOW_NEW_ACCOUNTS="true" ENV ALLOWPLUGINS="false" -ENV LOCALSESSIONRECORDING="false" -ENV MINIFY="true" +ENV LOCALSESSIONRECORDING="true" +ENV MINIFY="false" ENV WEBRTC="false" ENV IFRAME="false" ENV SESSION_KEY="" ENV REVERSE_PROXY="false" ENV REVERSE_PROXY_TLS_PORT="" +ENV ARGS="" RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ] && [ "$INCLUDE_MONGODBTOOLS" != "yes" ] && [ "$INCLUDE_MONGODBTOOLS" != "YES" ] \ && [ "$INCLUDE_MONGODBTOOLS" != "true" ] && [ "$INCLUDE_MONGODBTOOLS" != "TRUE" ]; then \ - echo -e "\e[0;31;49mInvalid value for build argument INCLUDE_MONGODBTOOLS, possible values: yes/true\e[;0m"; exit 1; \ + echo -e "\e[0;31;49mInvalid value for build argument INCLUDE_MONGODBTOOLS, possible values: yes/true\e[;0m"; exit 1; \ fi RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then apk add --no-cache mongodb-tools; fi @@ -81,11 +83,12 @@ COPY --from=builder /opt/meshcentral/meshcentral /opt/meshcentral/meshcentral COPY ./docker/startup.sh ./startup.sh COPY ./docker/config.json.template /opt/meshcentral/config.json.template -# install dependencies from package.json and nedb -RUN cd meshcentral && npm install && npm install nedb +# install dependencies from package.json +RUN cd meshcentral && npm install -RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.9.1; fi -RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2 saslprep semver nodemailer image-size wildleek@2.0.0 otplib@10.2.3; fi +# NOTE: ALL MODULES MUST HAVE A VERSION NUMBER AND THE VERSION MUST MATCH THAT USED IN meshcentral.js mainStart() +RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.13.0 saslprep@1.0.3; fi +RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2@1.16.0 semver@7.5.4 nodemailer@6.9.15 image-size@1.1.1 wildleek@2.0.0 otplib@10.2.3 yubikeyotp@0.2.0; fi EXPOSE 80 443 4433 @@ -93,6 +96,6 @@ EXPOSE 80 443 4433 VOLUME /opt/meshcentral/meshcentral-data VOLUME /opt/meshcentral/meshcentral-files VOLUME /opt/meshcentral/meshcentral-web -VOLUME /opt/meshcentral/meshcentral-backup +VOLUME /opt/meshcentral/meshcentral-backups CMD ["bash", "/opt/meshcentral/startup.sh"] diff --git a/docker/config.json.template b/docker/config.json.template index e463ef4c..cef4ad33 100644 --- a/docker/config.json.template +++ b/docker/config.json.template @@ -1,5 +1,5 @@ { - "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json", + "$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json", "settings": { "plugins":{"enabled": false}, "_mongoDb": null, @@ -21,9 +21,9 @@ "": { "_title": "MyServer", "_title2": "Servername", - "minify": true, + "minify": false, "NewAccounts": true, - "localSessionRecording": false, + "localSessionRecording": true, "_userNameIsEmail": true, "_certUrl": "my.reverse.proxy" } diff --git a/docker/readme.md b/docker/readme.md index 76995028..06bb43d1 100644 --- a/docker/readme.md +++ b/docker/readme.md @@ -10,12 +10,18 @@ | - docker-compose.yml ``` -# Templates: -## .env: +# Templates + +## .env +You can place the `config.json` file directly under `./meshcentral/data/`, or use the following `.env` file instead. + ```ini NODE_ENV=production -# initial mongodb-variables +USE_MONGODB=false +# set already exist mongo connection string url here +MONGO_URL= +# or set following init params for new mongodb, use it with docker-compose file with mongodb version MONGO_INITDB_ROOT_USERNAME=mongodbadmin MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd @@ -24,8 +30,7 @@ MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd # your hostname HOSTNAME=my.domain.com -USE_MONGODB=false -# set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy +# set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy REVERSE_PROXY=false REVERSE_PROXY_TLS_PORT= # set to true if you wish to enable iframe support @@ -40,9 +45,12 @@ ALLOWPLUGINS=false LOCALSESSIONRECORDING=false # set to enable or disable minification of json, reduces traffic MINIFY=true +# set this value to add extra arguments to meshcentral on startup (e.g --debug ldap) +ARGS= ``` -## docker-compose.yml: +## docker-compose.yml + ```yaml version: '3' @@ -63,12 +71,13 @@ services: # where file uploads for users live - ./meshcentral/user_files:/opt/meshcentral/meshcentral-files # location for the meshcentral-backups - this should be mounted to an external storage - - ./meshcentral/backup:/opt/meshcentral/meshcentral-backup + - ./meshcentral/backup:/opt/meshcentral/meshcentral-backups # location for site customization files - ./meshcentral/web:/opt/meshcentral/meshcentral-web ``` -## docker-compose.yml mongodb: +## docker-compose.yml mongodb + ```yaml version: '3' @@ -107,7 +116,7 @@ services: # where file uploads for users live - ./meshcentral/user_files:/opt/meshcentral/meshcentral-files # location for the meshcentral-backups - this should be mounted to an external storage - - ./meshcentral/backup:/opt/meshcentral/meshcentral-backup + - ./meshcentral/backup:/opt/meshcentral/meshcentral-backups # location for site customization files - ./meshcentral/web:/opt/meshcentral/meshcentral-web networks: diff --git a/docker/startup.sh b/docker/startup.sh index 4333f45f..da3f0b34 100644 --- a/docker/startup.sh +++ b/docker/startup.sh @@ -1,28 +1,34 @@ #!/bin/bash -if [ -f "meshcentral-data/${CONFIG_FILE}" ] - then - node meshcentral/meshcentral --configfile ${CONFIG_FILE} - else - cp config.json.template meshcentral-data/${CONFIG_FILE} - if ! [ -z "$USE_MONGODB" ] && [ "$USE_MONGODB" == "true" ]; then - sed -i "s/\"_mongoDb\": null/\"mongoDb\": \"mongodb:\/\/$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@mongodb:27017\"/" meshcentral-data/${CONFIG_FILE} +if [ -f "meshcentral-data/${CONFIG_FILE}" ]; then + node meshcentral/meshcentral --configfile "${CONFIG_FILE}" ${ARGS} +else + cp config.json.template meshcentral-data/"${CONFIG_FILE}" + if [ -n "$USE_MONGODB" ] && [ "$USE_MONGODB" == "true" ]; then + if [ -z "$MONGO_URL" ]; then + prefix="" + if [ -n "$MONGO_INITDB_ROOT_USERNAME" ] && [ -n "$MONGO_INITDB_ROOT_PASSWORD" ]; then + prefix="$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@" + fi + MONGO_URL="${prefix}mongodb:27017" fi - sed -i "s/\"cert\": \"myserver.mydomain.com\"/\"cert\": \"$HOSTNAME\"/" meshcentral-data/${CONFIG_FILE} - sed -i "s/\"NewAccounts\": true/\"NewAccounts\": $ALLOW_NEW_ACCOUNTS/" meshcentral-data/${CONFIG_FILE} - sed -i "s/\"enabled\": false/\"enabled\": $ALLOWPLUGINS/" meshcentral-data/${CONFIG_FILE} - sed -i "s/\"localSessionRecording\": false/\"localSessionRecording\": $LOCALSESSIONRECORDING/" meshcentral-data/${CONFIG_FILE} - sed -i "s/\"minify\": true/\"minify\": $MINIFY/" meshcentral-data/${CONFIG_FILE} - sed -i "s/\"WebRTC\": false/\"WebRTC\": $WEBRTC/" meshcentral-data/${CONFIG_FILE} - sed -i "s/\"AllowFraming\": false/\"AllowFraming\": $IFRAME/" meshcentral-data/${CONFIG_FILE} - if [ -z "$SESSION_KEY" ]; then - SESSION_KEY="$(cat /dev/urandom | tr -dc 'A-Za-z0-9!#$%&()*+,-./:;<=>?@[\]^_`{|}~' | fold -w 32 | head -n 1)"; - fi - sed -i "s/\"_sessionKey\": \"MyReallySecretPassword1\"/\"sessionKey\": \"$SESSION_KEY\"/" meshcentral-data/${CONFIG_FILE} - if [ "$REVERSE_PROXY" != "false" ]; then - sed -i "s/\"_certUrl\": \"my\.reverse\.proxy\"/\"certUrl\": \"https:\/\/$REVERSE_PROXY:$REVERSE_PROXY_TLS_PORT\"/" meshcentral-data/${CONFIG_FILE} - node meshcentral/meshcentral --configfile ${CONFIG_FILE} - exit - fi - node meshcentral/meshcentral --configfile ${CONFIG_FILE} --cert "$HOSTNAME" + sed -i "s/\"_mongoDb\": null/\"mongoDb\": \"mongodb:\/\/$MONGO_URL\"/" meshcentral-data/"${CONFIG_FILE}" + fi + sed -i "s/\"cert\": \"myserver.mydomain.com\"/\"cert\": \"$HOSTNAME\"/" meshcentral-data/"${CONFIG_FILE}" + sed -i "s/\"NewAccounts\": true/\"NewAccounts\": $ALLOW_NEW_ACCOUNTS/" meshcentral-data/"${CONFIG_FILE}" + sed -i "s/\"enabled\": false/\"enabled\": $ALLOWPLUGINS/" meshcentral-data/"${CONFIG_FILE}" + sed -i "s/\"localSessionRecording\": false/\"localSessionRecording\": $LOCALSESSIONRECORDING/" meshcentral-data/"${CONFIG_FILE}" + sed -i "s/\"minify\": false/\"minify\": $MINIFY/" meshcentral-data/"${CONFIG_FILE}" + sed -i "s/\"WebRTC\": false/\"WebRTC\": $WEBRTC/" meshcentral-data/"${CONFIG_FILE}" + sed -i "s/\"AllowFraming\": false/\"AllowFraming\": $IFRAME/" meshcentral-data/"${CONFIG_FILE}" + if [ -z "$SESSION_KEY" ]; then + SESSION_KEY="$(cat /dev/urandom | tr -dc 'A-Z0-9' | fold -w 48 | head -n 1)" + fi + sed -i "s/\"_sessionKey\": \"MyReallySecretPassword1\"/\"sessionKey\": \"$SESSION_KEY\"/" meshcentral-data/"${CONFIG_FILE}" + if [ "$REVERSE_PROXY" != "false" ]; then + sed -i "s/\"_certUrl\": \"my\.reverse\.proxy\"/\"certUrl\": \"https:\/\/$REVERSE_PROXY:$REVERSE_PROXY_TLS_PORT\"/" meshcentral-data/"${CONFIG_FILE}" + node meshcentral/meshcentral --configfile "${CONFIG_FILE}" ${ARGS} + exit + fi + node meshcentral/meshcentral --configfile "${CONFIG_FILE}" --cert "$HOSTNAME" ${ARGS} fi diff --git a/docs/Example configs/haproxy-with-sni-sample.cfg b/docs/Example configs/haproxy-with-sni-sample.cfg index a1f23cad..456c7466 100644 --- a/docs/Example configs/haproxy-with-sni-sample.cfg +++ b/docs/Example configs/haproxy-with-sni-sample.cfg @@ -20,6 +20,17 @@ backend sni-back use-server gitlabSNI if gitlab-sni use-server mc-SNI if mc-sni server mc-SNI 10.1.1.10:1443 send-proxy-v2-ssl-cn + +frontend cira-tcp-front + bind 10.1.1.10:4433 + mode tcp + option tcplog + tcp-request inspect-delay 5s + default_backend mc-cira-back + +backend cira-tcp-back + mode tcp + server mc-cira 10.1.1.30:4433 frontend mc-front-HTTPS mode http diff --git a/docs/docs/design/index.md b/docs/docs/design/index.md index 6c90729a..8ce7f819 100644 --- a/docs/docs/design/index.md +++ b/docs/docs/design/index.md @@ -2,7 +2,7 @@ ![](images/2022-05-15-12-57-36.png) -Design and Architecture Guide [as .pdf](https://meshcentral.com/info/docs/MeshCentral2DesignArchitecture.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral Design & Architecture v0.0.4.odt?raw=true) +Design and Architecture Guide [as .pdf](https://meshcentral.com/docs/MeshCentral2DesignArchitecture.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral Design & Architecture v0.0.4.odt?raw=true) ## Video Walkthru
@@ -108,29 +108,46 @@ Someone would think the server is rather simple when taking a look at the MeshCe ### Code files ``` - amtevents.js | Used to scan a local network for Intel AMT machines. - amtscanner.js | Used to run Intel AMT scripts from MeshCommander. - amtscript.js | Used to generate and perform certificate operations. - certoperations.js | Various commonly used methods. - common.js | Used to access the MongoDB or NeDB database. - db.js | Used to modify windows executables. - exeHandler.js | Used to insert credentials in an HTTP stream. - interceptor.js | Used to obtain and use a Let’s Encrypt certificate. - letsencrypt.js | Used to offload RSA sign to other CPU cores. - meshaccelerator.js | Used to communicate to agents. - meshagent.js | The is the main module, gets the server started. - meshcentral.js | Used to send SMTP mails. - meshmail.js | Used to relay agent and browser web socket connections. - meshrelay.js | MeshCentral server discovery when in LAN mode. - meshscanner.js | Used to communicate with browsers. - meshuser.js | Used to communicate to Intel® AMT CIRA. - mpsserver.js | Used for server-to-server communication. - multiserver.js | Performs password hash + salt. - pass.js | Used to handle HTTP traffic. - redirserver.js | Used to upgrade legacy MeshCentralv1 agents. - swarmserver.js | Handles HTTPS traffic. - webserver.js | Server background install on Windows. - winservice.js | Server background install on Windows. + amtevents.js | Used to decode Intel AMT WSMAN events. + amtmanager.js | Used to handle Intel AMT/CIRA things. + amtprovisioningserver.js | Used to Provision Intel AMT on a Local Network. + amtscanner.js | Used to scan a local network for Intel AMT machines. + amtscript.js | Used to run Intel AMT scripts from MeshCommander. + certoperations.js | Used to generate and perform certificate operations. + common.js | Various commonly used methods. + crowdsec.js | Used to handle all crowdsec security features + db.js | Used to access the MongoDB or NeDB database. + exeHandler.js | Used to modify windows executables. + firebase.js | Used to handle Google Firebase things. + interceptor.js | Used to insert credentials in an HTTP stream. + letsencrypt.js | Used to obtain and use a Let’s Encrypt certificate. + mcrec.js | Standalone Session Recording Indexer. + meshaccelerator.js | Used to offload RSA sign to other CPU cores. + meshagent.js | Used to communicate to agents. + meshbot.js | Sample bot to connect to meshcentral and preform various tasks + meshcentral.js | The is the main module, gets the server started. + meshctrl.js | MeshCtrl performs command line actions on a MeshCentral server. + meshcore.js | Main Agent Code that runs on your remote devices. + meshdesktopmultiplex.js | Used to handle remote desktop multiplexing. + meshdevicefile.js | Used to handle file download requests. + meshipkvm.js | Used to handle IP KVM integration + meshmail.js | Used to send SMTP mails. + meshmessaging.js | Used to handle all users messaging methods like 2FA. + meshrelay.js | Used to relay agent and browser web socket connections. + meshscanner.js | MeshCentral server discovery when in LAN mode. + meshsms.js | Used to handle all users sms methods. + meshuser.js | Used to communicate with browsers. + mpsserver.js | Used to communicate to Intel® AMT CIRA. + mqttbroker.js | Used to create/handle an MQTT broker (beta) + multiserver.js | Used for server-to-server communication. + pass.js | Performs password hash + salt. + redirserver.js | Used to handle HTTP traffic. + swarmserver.js | Used to upgrade legacy MeshCentralv1 agents. + webauthn.js | Handles all WebAuthN things. + webrelayserver.js | Used for all HTTP/HTTPS web relaying from agents. + webserver.js | Handles HTTPS traffic. + winservice.js | Server background install on Windows. + ``` At a high level, the MeshCentral.js file will get the server started. By default, it will start the webserver.js on port 443, redirectserver.js on port 80 and mpssrver.js on port 4433. The webserver.js file will create a meshuser.js or meshagent.js instance each time a user or agent connects. The other files support various usages, but this is the basic working on the server. diff --git a/docs/docs/how-to-contribute/images/translation-msg-output.png b/docs/docs/how-to-contribute/images/translation-msg-output.png new file mode 100644 index 00000000..ab94a484 Binary files /dev/null and b/docs/docs/how-to-contribute/images/translation-msg-output.png differ diff --git a/docs/docs/how-to-contribute/index.md b/docs/docs/how-to-contribute/index.md new file mode 100644 index 00000000..ed3d87aa --- /dev/null +++ b/docs/docs/how-to-contribute/index.md @@ -0,0 +1,56 @@ +# Contribute to MeshCentral + +## Contributing to MeshCentral via GitHub Pull Request + +If you're looking to contribute beyond translations, such as updating documentation or enhancing the software by adding features or fixing bugs, the process involves several key steps: + +1. **Fork the Repository:** Start by forking the [MeshCentral](https://github.com/Ylianst/MeshCentral) repository on GitHub. This creates a copy of the repository under your own GitHub account, allowing you to make changes without affecting the original project. + +2. **Make Your Changes** + - In your forked repository, create a new branch to keep your changes organized. This helps in managing different contributions separately. + - Make the necessary changes in your repository. This could involve updating documentation files or modifying code to add new features or fix bugs. + +3. **Review Your Changes:** Before submitting your work, carefully review the changes you’ve made. Check the "Files Changed" section on GitHub to ensure that all modifications are intended and correctly implemented. + +4. **Submit a Pull Request** + - Once your changes are ready and reviewed, submit a pull request (PR) from your branch to the `master` branch of the main MeshCentral repository. + - When creating the pull request, provide a clear and detailed description of what changes have been made and why. This helps maintainers understand the purpose of your contributions. + +5. **Wait for Review:** After submitting your pull request, wait for a project maintainer to review your contribution. Review time can vary depending on the complexity of the changes and the availability of the maintainers. + +6. **Respond to Feedback:** The maintainer may request further modifications or provide feedback on your pull request. Be prepared to make additional changes based on their suggestions to ensure that your contribution meets the project’s standards and requirements. + +7. **Final Steps:** Once your pull request is approved and merged by a maintainer, your contributions will be incorporated into the MeshCentral project. Congratulations, and thank you for helping improve MeshCentral! + +--- + +## Contribute to MeshCentral's Multilingual Support + +To make MeshCentral multilingual, your contributions are crucial. Follow these steps to translate the interface into various languages. + +1. **Remove Local Translations:** Delete `translate.json` from your `meshcentral-data` folder. This file contains your local copy of translations, which may become outdated as new features and texts are added. + +2. **Access MeshCentral:** Ensure you are logged into MeshCentral. +3. **Open Translation Tool:** Visit `https://YOURMESHCENTRALSERVER.COM/translator.htm` to access the translation interface. +4. **Choose a Language:** Select the language you wish to translate from the list provided. + +5. **Translate Text:** Use the search function or scroll through the list to find text segments you want to translate. Utilize the "show no translations only" checkbox to filter untranslated texts. +6. **Enter Translations:** For each text segment, enter your translation in the bottom box (not the top one) and click `SET (F1)`. +7. **Repeat Translation:** Continue translating by repeating steps 5 and 6 for other texts as desired. + +8. **Save and Apply Translations** + - Click `SAVE TO SERVER (F3)` to save your translations to `meshcentral-data/translate.json` locally in your MeshCentral server. + - Optionally, click `SAVE TO FILE (F4)` to download the `translate.json` file for offline review or sharing. + +9. **Deploy Translations:** Click `TRANSLATE SERVER` and allow some time for the process to complete (approximately 5-15 minutes depending on server specifications). This command line output will indicate when the translation is complete. +![](images/translation-msg-output.png) + +10. **Finalize Changes:** It’s crucial to restart MeshCentral to ensure that the translated files are picked up correctly. +11. **Share your translations:** Once a language translation is complete, take the latest `translation.json` and share it by emailing it to the maintainer (Ylianst, `ylianst@gmail.com`) or by submitting it to the MeshCentral GitHub repository via a pull request. + +--- + +#### Additional Information: + - If you make any changes to `default.handlebars`, run the translate server to propagate these modifications to the language-specific handlebar files located in `node_modules/meshcentral/views/translations`. + +By following these steps, you help MeshCentral support any language you choose, making it more accessible worldwide. By sharing your translations with us, you also help make these languages available to other users, improving the community and extending the software's reach. diff --git a/docs/docs/index.md b/docs/docs/index.md index c9b2b71b..fabdc903 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -4,8 +4,6 @@ MeshCentral is a full computer management web site. With MeshCentral, you can run your own web server to remotely manage and control computers on a local network or anywhere on the internet. Once you get the server started, create device group and download and install an agent on each computer you want to manage. A minute later, the new computer will show up on the web site and you can take control of it. MeshCentral includes full web-based remote desktop, terminal and file management capability. -To try out this software on the public server, please visit [MeshCentral.com/login](https://meshcentral.com/login). Be mindful that the public MeshCentral server comes with no guaranties, most should setup their own server. - For more information, [visit MeshCentral.com](https://www.meshcentral.com/). ## Social Media @@ -14,17 +12,17 @@ For more information, [visit MeshCentral.com](https://www.meshcentral.com/). [Reddit](https://www.reddit.com/r/MeshCentral/) -[Twitter](https://twitter.com/MeshCentral) +[BlueSky](https://bsky.app/profile/meshcentral.bsky.social) [BlogSpot](https://meshcentral2.blogspot.com/) ## Documentation -The [User's Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2UserGuide.pdf) contains information every adminstrator should know including usage, the server configuration file, databases, TLS offloading, Lets Encrypt, IP Filtering, Email setup, embedding, server port aliasing, reverse proxy setup, multi factor authentication, branding & terms of use, HashiCorp Vault support, and SSO. +The [User's Guide](meshcentral) contains information every administrator should know including usage, the server configuration file, databases, TLS offloading, Lets Encrypt, IP Filtering, Email setup, embedding, server port aliasing, reverse proxy setup, multi factor authentication, branding & terms of use, HashiCorp Vault support, and SSO. -The [Installation Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2InstallGuide.pdf) has detailed instructions for installing the MeshCentral Server on Windows 8.1, Windows 10, Windows 2012 R2, Amazon Linux 2, Raspberry Pi, Microsoft Azure, Google Cloud, Ubuntu 18, Ubuntu 16 and OpenBSD. +The [Installation Guide](install/install2.md) has detailed instructions for installing the MeshCentral Server on Windows 8.1, Windows 10, Windows 2012 R2, Amazon Linux 2, Raspberry Pi, Microsoft Azure, Google Cloud, Ubuntu 18, Ubuntu 16 and OpenBSD. -The [Design and Architecture Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2DesignArchitecture.pdf) is a short document that includes information on the design overview, dependencies, source code descriptions of each file, certificates, TLS security, the agent to server handshake, browser to agent relay and WebRTC and the messenger service. +The [Design and Architecture Guide](design) is a short document that includes information on the design overview, dependencies, source code descriptions of each file, certificates, TLS security, the agent to server handshake, browser to agent relay and WebRTC and the messenger service. ## Video Tutorials diff --git a/docs/docs/install/index.md b/docs/docs/install/index.md index 59e7b8da..988cf099 100644 --- a/docs/docs/install/index.md +++ b/docs/docs/install/index.md @@ -13,7 +13,7 @@ That's it. MeshCentral will set itself up and start managing computers on your l For Windows users, you can download the MeshCentral Installer that will automate installation of NodeJS and provide basic configuration of the server. This option is not recommended for advanced users. -[Win32 MeshCentral Installer](https://meshcentral.com/info/tools/MeshCentralInstaller.exe) +[Win32 MeshCentral Installer](https://meshcentral.com/tools/MeshCentralInstaller.exe) By default, MeshCentral will use NeDB as this is the built-in database. For more advanced users, it's recommended to switch to using MongoDB. MeshCentral can be installed on a very small server. A [Raspberry Pi](https://www.raspberrypi.org/) or [AWS t3.nano running Amazon Linux 2 instance](https://aws.amazon.com/ec2/pricing/on-demand/) for 5$ a month will do just fine for managing up to a few hundred devices. @@ -23,10 +23,10 @@ You can run the MeshCentral Server with --help to get options for background ins Once you get MeshCentral installed, the first user account that is created will be the server administrator. So, don't delay and navigate to the login page and create a new account. You can then start using your server right away. A lot of the fun with MeshCentral is the 100's of configuration options that are available in the config.json file. You can put your own branding on the web pages, setup a SMTP email server, SMS services and much more. -You can look [here for simple config.json](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config.json), [here for a more advanced configuration](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config-advanced.json) and [here for all possible configuration options](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json). You can also take a look at the [MeshCentral User's Guide](https://meshcentral.com/info/docs/MeshCentral2InstallGuide.pdf) and [tutorial videos](https://meshcentral.com/info/tutorials.html) for additional help. +You can look [here for simple config.json](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config.json), [here for a more advanced configuration](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config-advanced.json) and [here for all possible configuration options](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json). You can also take a look at the [tutorial videos](https://www.youtube.com/@MeshCentral/videos) for additional help. ## Video Walkthru
-
\ No newline at end of file +
diff --git a/docs/docs/install/install2.md b/docs/docs/install/install2.md index 94efa251..39312467 100644 --- a/docs/docs/install/install2.md +++ b/docs/docs/install/install2.md @@ -4,6 +4,45 @@ This guide is specifically intended to help users install MeshCentral from start to finish. Once installed, you can take a look at the MeshCentral user’s guide for information on how to configure MeshCentral for your specific use. In this document, we will look at installing MeshCentral on AWS Linux, Raspberry Pi and Ubuntu. +## Docker + + + +``` +docker pull ghcr.io/ylianst/meshcentral:master +``` + +!!!warning + Do not use the built in mesh update function. Update docker the docker way. + +### Docker Compose + +``` +version: '3' +services: + meshcentral: + restart: unless-stopped # always restart the container unless you stop it + image: ghcr.io/ylianst/meshcentral:1.1.27 # 1.1.27 is a version number OR use master for the master branch of bug fixes + ports: + - 80:80 # HTTP + - 443:443 # HTTPS + - 4433:4433 # AMT (Optional) + volumes: + - data:/opt/meshcentral/meshcentral-data # config.json and other important files live here + - user_files:/opt/meshcentral/meshcentral-files # where file uploads for users live + - backup:/opt/meshcentral/meshcentral-backups # location for the meshcentral backups - this should be mounted to an external storage + - web:/opt/meshcentral/meshcentral-web # location for site customization files +volumes: + data: + driver: local + user_files: + driver: local + backup: + driver: local + web: + driver: local +``` + ## Quick Start For some who want to skip this document entirely, there are quick install scripts that will get a MeshCentral2 instance up and running on Linux in a few minutes. These scripts will pretty much do what this document explains very rapidly. Right now, there are two such scripts available: @@ -13,7 +52,7 @@ For some who want to skip this document entirely, there are quick install script For Amazon EC2 users, that want to manage 100 devices or less. Launch a t3.nano or t3.micro EC2 instance with Amazon Linux 2 with TCP ports 22 (SSH), 80 (HTTP), 443 (HTTPS) and 4433 (CIRA) open. Then login as `ec2-user` and enter the following commands: ``` -wget http://info.meshcentral.com/scripts/mc-aws-linux2.sh +wget https://meshcentral.com/scripts/mc-aws-linux2.sh chmod 755 mc-aws-linux2.sh ./mc-aws-linux2.sh ``` @@ -21,7 +60,7 @@ chmod 755 mc-aws-linux2.sh This will download the fast install script and once run, will install nodejs, meshcentral, setup systemd and start the server. For a larger instance like a t3.small, t3.medium or larger you can run the following that does the same but also installs MongoDB. ``` -wget http://info.meshcentral.com/scripts/mc-aws-linux2-mongo.sh +wget https://meshcentral.com/scripts/mc-aws-linux2-mongo.sh chmod 755 mc-aws-linux2-mongo.sh ./mc-aws-linux2-mongo.sh ``` @@ -33,13 +72,19 @@ After these scripts are run, try accessing the server using a browser. MeshCentr For 100 devices or less, launch an instance of Ubuntu 18.04 using a small B1s instance. Set the username to `default` in all lower case and open ports 22, 80, 443 and 3389 using the basic network profile. Then start the instance and run the following lines. ``` -wget http://info.meshcentral.com/scripts/mc-azure-ubuntu1804.sh +wget https://meshcentral.com/scripts/mc-azure-ubuntu1804.sh chmod 755 mc-azure-ubuntu1804.sh ./mc-azure-ubuntu1804.sh ``` In this situation, port 3389 will be used to receive Intel AMT CIRA connections instead of port 4433. After these scripts are run, try accessing the server using a browser. MeshCentral will take a minute or two to create certificates after that, the server will be up. The first account to be created will be the site administrator – so don’t delay and create an account right away. Once running, move on to the MeshCentral’s user’s guide to configure your new server. +### Elestio + +You can deploy MeshCentral on Elestio using one-click deployment. Elestio handles version updates, maintenance, securtiy, backups, etc. Additionally, Elestio supports MeshCentral by providing revenue share so go ahead and click below to deploy and start using. + +[![Deploy on Elestio](https://elest.io/images/logos/deploy-to-elestio-btn.png)](https://elest.io/open-source/meshcentral) + ## Server Security - Adding Crowdsec MeshCentral has built-in support for a CrowdSec bouncer. This allows MeshCentral to get threat signals from the community and block or CAPTCHA requests coming from known bad IP addresses. @@ -884,7 +929,7 @@ The last line will run MeshCentral manually and allow it to install any missing ``` sudo chown -R meshcentral:meshcentral /opt/meshcentral -sudo chmod 755 –R /opt/meshcentral/meshcentral-* +sudo chmod -R 755 /opt/meshcentral/meshcentral-* ``` To make this work, you will need to make MeshCentral work with MongoDB because the /meshcentral-data folder will be read-only. In addition, MeshCentral will not be able to update itself since the account does not have write access to the /node_modules files, so the update will have to be manual. First used systemctl to stop the MeshCentral server process, than use this: @@ -901,7 +946,7 @@ This will perform the update to the latest server on NPM and re-set the permissi MeshCentral allows users to upload and download files stores in the server’s `meshcentral-files` folder. In an increased security setup, we still want the server to be able to read and write files to this folder and we can allow this with: ``` -sudo chmod 755 –R /opt/meshcentral/meshcentral-files +sudo chmod -R 755 /opt/meshcentral/meshcentral-files ``` If you plan on using the increased security installation along with MeshCentral built-in Let’s Encrypt support you will need to type the following commands to make the `letsencrypt` folder in `meshcentral-data` writable. @@ -909,11 +954,19 @@ If you plan on using the increased security installation along with MeshCentral ``` sudo mkdir /opt/meshcentral/meshcentral-data sudo mkdir /opt/meshcentral/meshcentral-data/letsencrypt -sudo chmod 755 –R /opt/meshcentral/meshcentral-data/letsencrypt +sudo chmod -R 755 /opt/meshcentral/meshcentral-data/letsencrypt ``` This will allow the server to get and periodically update its Let’s Encrypt certificate. If this is not done, the server will generate an `ACCES: permission denied` exception. +### Restore backup in Ubuntu + +- Stop Meshcentral service `sudo systemctl stop meshcentral.service` +- In your old server, get your backup : meshcentral-data folder, and mongodump-xxxx.archive +- In the new server, replace the actual meshcentral-data with your backup (it will handle your LestEncrypt cert also) +- Restore mongodb : mongorestore --archive=mongodump-xxxx.archive +- Restart meshcentral.service `sudo systemctl start meshcentral.service` + ## Microsoft Azure In this section, we will look installing MeshCentral on Microsoft Azure. Microsoft Azure offers many operating system options and we will be selecting `Ubuntu Server` as our choice. From the Azure portal, we select `Virtual machines` on the left and `Add`. diff --git a/docs/docs/intelamt/images/amtprovisioningserver.png b/docs/docs/intelamt/images/amtprovisioningserver.png new file mode 100644 index 00000000..fd64e618 Binary files /dev/null and b/docs/docs/intelamt/images/amtprovisioningserver.png differ diff --git a/docs/docs/intelamt/index.md b/docs/docs/intelamt/index.md index 2fcc0bbc..ad3c4986 100644 --- a/docs/docs/intelamt/index.md +++ b/docs/docs/intelamt/index.md @@ -49,6 +49,16 @@ Intel® AMT If you are looking into managing remote computers that would be difficult to physically get access to for remote support or maintenance, one should probably look at getting a PC with Intel AMT. +## Bare-Metal Activation Server + +The `AmtProvisioningServer` section in the `settings` section of the config.json will enable this feature. MeshCentral will then listen for activation requests, match against your ACM activation certificates and if everything goes well, will activate and add the device to a Intel AMT only device group. No agent or MeshCMD is involved. + +This bare-metal activation server is not enabled by default and only makes sense when activating devices on the local network. + +Once enabled, Intel AMT can send “hello” data to the MeshCentral provisioning server on port 9971 and MeshCentral will respond by connecting back, authenticating, and activating Intel AMT. MeshCentral will then log the event, add the device to a pre-defined agent-less device group and complete any remaining configuration. A trusted CA certificate is required to perform this operation fully automatically. + +![baremetal](images/amtprovisioningserver.png) + ## MeshCentral Group Types Once MeshCentral is installed, a user will typically create a new device group. Here is the first hint that MeshCentral supports Intel AMT. Device groups come in two types. You can manage using a software agent, or using Intel AMT only. @@ -175,12 +185,22 @@ Once setup, Intel AMT will not automatically activate to Intel AMT unless the ri - The name “meshcentral.com” by have been set as “Trusted FQDN” in MEBx. - The name “meshcentral.com” must have been set using a USB key with a setup.bin file. +
+ +
+ Once Intel AMT is in a situation where ACM activation can occur, the activation command line can be run or the Mesh Agent will detect this situation and ask the server to perform activation. ![](images/2022-05-16-23-16-05.png) The best way to test this feature is to create an “Intel AMT only” device group and run the MeshCMD command on the remote system to perform activation. If there is a problem, this process should clearly display why ACM activation fails. +!!!note + Activation over wifi has some additional issues.
+ First you need to add your WiFi access point to that wifi configuration to allow CSME to take over WiFi when OS is not functioning. Then it should work.
+ Please also make sure you install Intel WiFi driver and Intel LMS package. It should work. You can detach the ethernet and then try connecting to that device using the IP address acquired by WiFi interface. + See [Open AMT Cloud Toolkit](https://www.intel.com/content/www/us/en/developer/topic-technology/edge-5g/tools/open-amt-cloud-toolkit.html) project - a close relative to this project. It has an AMT activation component and newer remote provisioning client can activate locally and also can manage Wi-Fi profile. + ## Intel AMT MEI and LMS Intel Active Management Technology (Intel AMT) can communicate to the local platform using the Management Engine Interface (MEI). We show how your can use that to get Intel AMT information. For more advanced usages, you need to connect using TCP and TLS which requires Intel Local Manageability Service (LMS). We show how MeshCentral's Mesh Agent and MeshCMD have a small version of LMS built-in and how it works diff --git a/docs/docs/meshcentral/agents.md b/docs/docs/meshcentral/agents.md index 43279e6a..6cba2f14 100644 --- a/docs/docs/meshcentral/agents.md +++ b/docs/docs/meshcentral/agents.md @@ -50,7 +50,7 @@ For OSx 11+ including Big Sur, Monterey and later ## Apple macOS -For macOS 10.x including Catalina, Mojave, High Sierra, Sierra, El Capitan, Yosemite, Mavericks, Mountain Lion and earlier +For macOS 10.x including Catalina, Mojave, High Sierra, Sierra, El Capitan, Yosemite, Mavericks, Mountain Lion and earlier. ## Mobile Device (Android) @@ -59,3 +59,304 @@ For macOS 10.x including Catalina, Mojave, High Sierra, Sierra, El Capitan, Yose See [Assistant](assistant.md) ## Apple MacOS Binary Installer + +## Agent Commands + +**agentmsg** +: Add/Remove badged messages to the device's web ui +``` + agentmsg add "[message]" [iconIndex] + agentmsg remove [index] + agentmsg list +``` +**agentsize** +: Returns the binary size of the agent + +**agentupdate** +: Manually trigger an agent self-update + +**alert** +: Display an alert dialog on the logged in session +``` +alert TITLE, CAPTION [, TIMEOUT] +``` + +**amt** + +**amtconfig** + +**amtevents** + +**apf** + +**args** + +**av** +: Displays Antivirus State + +**coredump** + +**coreinfo** + +**cpuinfo** + +**cs** +: Display Windows Connected Standby State + +**dbcompact** +: Compacts the agent database + +**dbget** + +**dbkeys** + +**dbset** + +**dnsinfo** +: Display DNS server info + +**domain** +: Display domain metadata + +**errorlog** + +**eval** +: executes javascript on the agent +``` +eval [code] +``` + +**fdcount** +: Returns the number of active descriptors in the event loop + +**fdsnapshot** +: Returns detailed descriptor/handle/timer metadata + +**getclip** +: Fetches clipboard data from agent + +**getscript** + +**help** +: Returns the list of supported console commands + +**httpget** + +**info** +: Returns general information about the agent, such as connected state, loaded modules, LMS state, etc + +**kill** +: Sends a SIGKILL signal to the specified PID +``` +kill [pid] +``` + +**kvmmode** +: Displays the KVM Message Format + +**location** +: Displays saves location information about the connected agent + +**lock** + +**log** +: Writes a message to the logfile +``` +log [message] +``` + +**ls** +: Enumerates the files in the agent's install folder + +**mousetrails** +: Enables/Disables Mouse Trails Accessibility on Windows. To change setting, specify a positive integer representing the number of latent cursors, where 0 is disable +``` +mousetrails [n] +``` + +**msh** +: Displays the loaded msh settings file + +**netinfo** +: Displays network interface information + +**notify** +: Display a notification on the web interface + +**openurl** + +**osinfo** +: Displays OS information + +**parseuri** +: Parses the specified URI, and displays the parsed output +``` +parseuri [uri] +``` + +**plugin** +: Invokes a plugin +``` +plugin [pluginName] [args] +``` + +**power** +: Performs the specified power action +``` +power [action] + LOGOFF = 1 + SHUTDOWN = 2 + REBOOT = 3 + SLEEP = 4 + HIBERNATE = 5 + DISPLAYON = 6 + KEEPAWAKE = 7 + BEEP = 8 + CTRLALTDEL = 9 + VIBRATE = 13 + FLASH = 14 +``` + +**print** + +**privacybar** +: Sets/Gets the default pinned state of the Privacy Bar on windows +``` +privacybar [PINNED|UNPINNED] +``` + +**ps** +: Enumerates processes on the agent + +**rawsmbios** +: Fetches the raw smbios table + +**safemode** +: Sets/Gets the SAFEMODE configuration of the agent, as well as the next boot state. +``` +safemode (ON|OFF|STATUS) +``` + +**scanwifi** +: Scans the available Wifi access points, and displays the SSID and Signal Strength + +**service** +: Shortcut to be able to restart the agent service +``` +service status|restart +``` + +**setclip** +: Sets clipboard data to the agent +``` +setclip [text] +``` + +**setdebug** +: Sets the location target for debug messages +``` +setdebug [target] +0 = Disabled +1 = StdOut +2 = This Console +* = All Consoles +4 = WebLog +8 = Logfile +``` + +**smbios** +: Displays the parsed SMBIOS metadata + +**startupoptions** +: Displays the command-line options that the agent was started with + +**sysinfo** +: Collects and displays telemetry on the platform + +**task** + +**taskbar** +: Hides or shows the Windows System task bar, optionally on the specified Terminal Server Session ID +``` +taskbar HIDE|SHOW [TSID] +``` + +**timerinfo** +: Displays metadata about any configured timers on the event loop + +**toast** +: Displays a toast message on the logged in user's session +``` +toast [message] +``` + +**translations** +: Shows the currently configured translations + +**type** +``` +type (filepath) [maxlength] +``` + +**uac** +: Get/Sets the Windows UAC mode +``` +uac [get|interactive|secure] +``` + +**unzip** +``` +unzip input, destination +``` +: Unzips the specified file + +**users** +: Enumerates the logged in users on the system + +**versions** +: Displays version information about the agent + +**vm** +: Detects if the system is a Virtual Machine + +**volumes** +: Displays volume information reported by the OS + +**wakeonlan** +: Sends wake-on-lan packets to the specified MAC address +``` +wakeonlan [mac] +``` + +**wallpaper** +: Gets/Toggles the logged in user's desktop background image +``` +wallpaper (GET|TOGGLE) +``` + +**wpfhwacceleration** +: Enable/Disable WPF HW Acceleration on Windows +``` +wpfhwacceleration (ON|OFF|STATUS) +``` + +**wsclose** + +**wsconnect** + +**wslist** + +**wssend** + +**zip** +``` +zip (output file name), input1 [, input n] +``` + +## Agent msh options + +You can find a full list of options for the agent [here](https://github.com/Ylianst/MeshAgent?tab=readme-ov-file#msh-format) + +`skipmaccheck=1`: Will not regenerate the agents nodeid and cause duplication of the agent when the MAC address changes. + +You can add options to your .msh on agent install with [this](https://github.com/Ylianst/MeshCentral/blob/15ff7d12a1e4e5d78936b473ea207b7e02b8ff26/meshcentral-config-schema.json#L2504) diff --git a/docs/docs/meshcentral/assistant.md b/docs/docs/meshcentral/assistant.md index 5da427ef..0462df3e 100644 --- a/docs/docs/meshcentral/assistant.md +++ b/docs/docs/meshcentral/assistant.md @@ -14,16 +14,28 @@ ![agent invite code](images/assistant_agent_code.png) -## Agent Invitation Link - -For web page customization: +## Agent Invitation +Click on the 'Invite' button next to the device group name to access it. +### Link Invitation +For link invitation web page customization: 1. Alongside `meshcentral-data` create a folder called `meshcentral-web` 2. Create a `views` folder in it and copy the file `node_modules/meshcentral/views/invite.handlebars` into it. -3. That copy will be served instead of the default one, you can customize as you want. +3. That copy will be served instead of the default one, so you can customize it as you want. ![agent invite code](images/assistant_invitation_link.png) +### Email Invitation +This option will show up if you have an SMTP email server set up with MeshCentral. + +For invitation email customization: + +1. Alongside `meshcentral-data` create a folder called `meshcentral-web` +2. Create an `emails` folder in it and copy the files `node_modules/meshcentral/emails/mesh-invite.txt` and `node_modules/meshcentral/emails/mesh-invite.html` into it. +3. These copies will be used instead of the default ones, so you can customize them as you want. + +![email-invitation](images/email-invitation.png) + ## Email notification You can also get an email notification when someone clicks the "Request Help" button in the Assistant agent. diff --git a/docs/docs/meshcentral/codesigning.md b/docs/docs/meshcentral/codesigning.md index 8fd46f7b..25e7a37a 100644 --- a/docs/docs/meshcentral/codesigning.md +++ b/docs/docs/meshcentral/codesigning.md @@ -73,7 +73,7 @@ When doing sign/unsign, you can also change resource properties of the generated ## Automatic Agent Code Signing -If you want to self-sign the mesh agent so you can whitelist the software in your AV, and lock it to your server and organization. +If you want to self-sign the mesh agent so you can whitelist the software in your AV, as well as lock it to your server and organization:
diff --git a/docs/docs/meshcentral/config.md b/docs/docs/meshcentral/config.md index 439a1dc5..92824f63 100644 --- a/docs/docs/meshcentral/config.md +++ b/docs/docs/meshcentral/config.md @@ -1,1354 +1,42 @@ # Configuration Options -All possible configuration of MeshCentral can be found in this file: +There are MANY configuration options available with meshcentral, search this file for options: -See description for information about each item. +Some options you can find relate to: -```json -{ - "id": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json", - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "MeshCentral configuration file schema", - "type": "object", - "properties": { - "settings": { - "type": "object", - "properties": { - "cert": { "type": "string", "description": "Set this to the primary DNS name of this MeshCentral server." }, - "keepCerts": { "type": "boolean", "default": false, "description": "Force MeshCentral to use the HTTPS and MPS certificates even if the name does not match the expected DNS value." }, - "mongoDb": { "type": "string", "default": null }, - "mongoDbName": { "type": "string" }, - "mongoDbChangeStream": { "type": "boolean", "default": false }, - "mongoDbBulkOperations": { "type": "boolean", "default": false }, - "mariaDB": { - "type": "object", - "description": "Add this section to connect MeshCentral to a MariaDB database instance.", - "properties": { - "host": { "type": "string", "description": "MariaDB hostname" }, - "user": { "type": "string", "description": "MariaDB username" }, - "port": { "type": "number", "description": "MariaDB port number" }, - "password": { "type": "string", "description": "MariaDB password" }, - "connectionLimit": { "type": "number", "description": "MariaDB connection limit" }, - "database": { "type": "string", "default": "meshcentral", "description": "Name of MariaDB database used" }, - "awsrds": { "type": "boolean", "default": false, "description": "Set true to resolve LOCK TABLE permissions on AWS RDS." }, - "ssl": { - "type": "object", - "description": "SSL Options. Set to true (boolean) for default options.", - "properties": { - "caCertPath": { "type": "string", "description": "Absolute path to the CA certificate. Required for self-signed certificates" }, - "clientCertPath": { "type": "string", "description": "Absolute path to the client certificate. Required for two-way SSL Authentication" }, - "clientKeyPath": { "type": "string", "description": "Absolute path to the client key. Required for two-way SSL Authentication" }, - "dontCheckServerIdentity": { "type": "boolean", "description": "Set true to not check the server hostname during verification" } - } - } - } - }, - "sqlite3": { "type": "boolean", "default": false, "description": "Set true to use SQLite3 as a local MeshCentral database." }, - "mySQL": { - "type": "object", - "description": "Add this section to connect MeshCentral to a MySQL database instance.", - "properties": { - "host": { "type": "string", "description": "MySQL hostname" }, - "port": { "type": "number", "description": "MySQL port number" }, - "user": { "type": "string", "description": "MySQL username" }, - "password": { "type": "string", "description": "MySQL password" }, - "database": { "type": "string", "default": "meshcentral", "description": "Name of MySQL database used" }, - "awsrds": { "type": "boolean", "default": false, "description": "Set true to resolve LOCK TABLE permissions on AWS RDS." }, - "ssl": { - "type": "object", - "description": "SSL Options. Set to true (boolean) for default options.", - "properties": { - "caCertPath": { "type": "string", "description": "Absolute path to the CA certificate. Required for self-signed certificates" }, - "clientCertPath": { "type": "string", "description": "Absolute path to the client certificate. Required for two-way SSL Authentication" }, - "clientKeyPath": { "type": "string", "description": "Absolute path to the client key. Required for two-way SSL Authentication" }, - "dontCheckServerIdentity": { "type": "boolean", "description": "Set true to not check the server hostname during verification" } - } - } - } - }, - "postgres": { - "type": "object", - "description": "Add this section to connect MeshCentral to a PostgreSQL database instance.", - "properties": { - "host": { "type": "string", "description": "PostgreSQL hostname" }, - "user": { "type": "string", "description": "PostgreSQL username" }, - "port": { "type": "number", "description": "PostgreSQL port number" }, - "password": { "type": "string", "description": "PostgreSQL password" }, - "database": { "type": "string", "default": "meshcentral", "description": "Name of PostgreSQL database used" } - } - }, - "acebase": { - "type": "object", - "description": "Add this section to enable AceBase database support, this is a local database system much like NeDB.", - "properties": { "sponsor": { "type": "boolean", "default": false, "description": "Set true to remove the AceBase banner on startup." } } - }, - "WANonly": { "type": "boolean", "default": false, "description": "When enabled, only MeshCentral WAN features are enabled and agents will connect to the server using a well known DNS name." }, - "LANonly": { "type": "boolean", "default": false, "description": "When enabled, only MeshCentral LAN features are enabled and agents will find the server using multicast LAN packets." }, - "maintenanceMode": { "type": "boolean", "default": false, "description": "When enabled the server is in maintenance mode, only administrators can login. Use the maintenance command in server console to change." }, - "certificatePrivateKeyPassword": { "type": "array", "default": null, "description": "List of passwords used to decrypt PKCK#8 .key files that are in the meshcentral-data folder." }, - "sessionTime": { "type": "integer", "default": 60, "description": "Duration of a session cookie in minutes. Changing this affects how often the session needs to be automatically refreshed." }, - "sessionKey": { "type": "string", "default": null, "description": "Password used to encrypt the MeshCentral web session cookies. If null, a random one is generated each time the server starts." }, - "sessionSameSite": { "type": "string", "default": "lax", "enum": ["strict", "lax", "none"] }, - "dbEncryptKey": { "type": "string", "default": null, "description": "This value is only valid when used with NeDB, sets the database encryption and decryption key." }, - "dbRecordsEncryptKey": { "type": "string", "default": null, "description": "With any database, encrypt and decrypt sensitive information within records using this secret key." }, - "dbRecordsDecryptKey": { "type": "string", "default": null, "description": "With any database, decrypt sensitive information within records using this secret key, don't use a key to encrypt records." }, - "dbExpire": { - "type": "object", - "properties": { - "events": { "type": "integer", "default": 1728000, "description": "Amount of time in seconds that events are kept in the database." }, - "powerevents": { "type": "integer", "default": 864000, "description": "Amount of time in seconds that device power events are kept in the database." }, - "statsevents": { "type": "integer", "default": 2592000, "description": "Amount of time in seconds that server statistics are kept in the database." } - } - }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 443, "description": "Ths port of the main HTTPS server." }, - "portBind": { "type": "string", "description": "When set, bind the HTTPS main port to a specific network address." }, - "aliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null, "description": "The actual main port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." }, - "redirPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 80, "description": "This is a HTTP web server port that mostly redirects users to the HTTPS port but does provide some other services, 0 will turn this port off." }, - "redirPortBind": { "type": "string", "description": "When set, bind the HTTP redirection port to a specific network address." }, - "redirAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "The actual redirection port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." }, - "relayPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 0, "description": "When set, a web relay web server is bound to this port and will allow user access to remote web sites." }, - "relayAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null, "description": "The actual relay port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." }, - "relayDNS": { "type": "string", "default": null, "description": "When set, relayPort value is ignored. Set this to a DNS name the points to this server. When the server is accessed using the DNS name, the main web server port is used as a web relay port." }, - "agentPort": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "When set, enabled a new HTTPS server port that only accepts agent connections." }, - "agentPortBind": { "type": "string", "description": "When set, binds the agent port to a specific network interface." }, - "agentAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "When set, indicates the actual publicly visible agent-only port. If not set, the AgentPort value is used." }, - "agentAliasDNS": { "type": "string", "format": "hostname", "description": "When set, specified the DNS name used by agents to connect to the agent-only port." }, - "agentPortTls": { "type": "boolean", "default": true, "description": "Indicates if the agent-only port must perform TLS, this should be set to false if TLS is performed in front of this server." }, - "agentLogDump": { "type": "boolean", "default": false, "description": "Automatically downloads all agent error logs into meshcentral-data/agenterrorlogs.txt." }, - "agentCoreDump": { "type": "boolean", "default": false, "description": "Automatically activates and transfers any agent crash dump files to the server in meshcentral-data/coredumps." }, - "agentCoreDumpUsers": { "type": "array", "description": "List of non-administrator users that have access to mesh agent crash dumps." }, - "agentSignLock": { "type": "boolean", "default": false, "description": "When code signing an agent using authenticode, lock the agent to only allow connection to this server. (This is in testing, the default value will change to true in the future)." }, - "agentTimeStampServer": { "type": [ "boolean", "string" ], "default": "http://timestamp.comodoca.com/authenticode", "description": "The time stamping server to use when code signing Windows executables. When set to false, the executables are not time stamped." }, - "agentTimeStampProxy": { "type": [ "boolean", "string" ], "description": "The HTTP proxy to use when contacting the time stamping server, if false, no proxy is used. By default, the npmproxy value is used." }, - "ignoreAgentHashCheck": { "type": [ "boolean", "string" ], "default": false, "description": "When true, the agent no longer checked the TLS certificate of the server. This should be used for debugging only. You can also set this to a comma separated list of IP addresses to ignore, for example: \"192.168.2.100,192.168.1.0/24\"." }, - "exactPorts": { "type": "boolean", "default": false, "description": "When set to true, MeshCentral will only grab the required TCP listening ports or fail. It will not try to use the next available port of it's busy." }, - "allowLoginToken": { "type": "boolean", "default": false }, - "StrictTransportSecurity": { "type": ["boolean", "string"], "default": null, "description": "Controls the Strict-Transport-Security header, default is 1 year. Set to false to remove, true to force enable, or string to set a custom value. If set to null, MeshCentral will enable if a trusted certificate is set." }, - "allowFraming": { "type": "boolean", "default": false, "description": "When enabled, the MeshCentral web site can be embedded within another website's iframe." }, - "cookieIpCheck": { "type": [ "string", "boolean" ], "default": "lax", "enum": ["strict", "lax", "none"] }, - "cookieEncoding": { "type": "string", "enum": [ "hex", "base64" ], "default": "base64", "description": "Encoding format of cookies in the HTTP headers, this is typically Base64 but some reverse proxies will require HEX." }, - "webRTC": { "type": "boolean", "default": false, "description": "When enabled, allows use of WebRTC to allow direct network traffic between the agent and browser." }, - "nice404": { "type": "boolean", "default": true, "description": "By default, a nice looking 404 error page is displayed when needed. Set this to false to disable it." }, - "selfUpdate": { "type": "boolean", "default": false, "description": "When true, this server will attempt to self-update everyday after midnight." }, - "cleanNpmCacheOnUpdate": { "type": "boolean", "default": false, "description": "When true, run \"npm cache clean --force\" to reclaim disk space." }, - "browserPing": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the browser at x seconds interval and expects a response from the browser." }, - "browserPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the browser at x seconds interval." }, - "agentsInRam": { "type": "boolean", "default": false, "description": "Loads all agent binaries in RAM for faster agent updates." }, - "agentPing": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval and expects a response from the agent." }, - "agentPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval." }, - "amtManager": { "type": "boolean", "default": true, "description": "When enabled, MeshCentral will automatically monitor and manage Intel AMT devices." }, - "orphanAgentUser": { "type": "string", "default": null, "description": "If an agent attempts to connect to a unknown device group, automatically create a new device group and grant access to the specified user. Example: admin" }, - "agentIdleTimeout": { "type": "integer", "minimum": 1, "default": 150 ,"description": "How much time in seconds with no traffic from an agent before dropping the agent connection." }, - "webPageLengthRandomization": { "type": "boolean", "default": true, "description": "Adds a random length string to generated web pages to mitigate a BREACH attack." }, - "compression": { "type": "boolean", "default": true, "description": "Enables GZIP compression for web requests." }, - "wsCompression": { "type": "boolean", "default": false, "description": "Enables server-side, websocket per-message deflate compression." }, - "agentWsCompression": { "type": "boolean", "default": true, "description": "Enables agent-side, websocket per-message deflate compression. wscompression must also be true for this to work." }, - "noAgentUpdate": { "type": "integer", "default": 0, "description": "Set to 1 to present the server from updating any agent." }, - "agentUpdateSystem": { "type": "integer", "default": 1, "description": "When set to 2, all agents that need to be updated will use the meshcore.js update system. With the default value of 1, the native update system is used." }, - "temporaryAgentUpdate": { "type": "boolean", "default": true, "description": "Set to false to not allow temporary agents to be updated." }, - "amtScanner": { "type": "boolean", "default": true, "description": "Set to false to disable Intel AMT scanning on the local network, this is already disabled in WAN mode." }, - "meshScanner": { "type": "boolean", "default": true, "description": "Set to false to disable agent multicast scanning on the local network, this is already disabled in WAN mode." }, - "meshErrorLogPath": { "type": "string" }, - "npmPath": { "type": "string" }, - "npmProxy": { "type": "string", "format": "uri" }, - "allowHighQualityDesktop": { "type": "boolean", "default": true, "description": "When false, users will only be able to set remote desktop image quality to 60%, this can reduce server bandwidth usage." }, - "webPush": { - "type": "object", - "description": "When set with a valid email address, enables the MeshCentral web push notification feature. Allows administrators to send browser notifications to users even if they are not looking at the MeshCentral web site.", - "additionalProperties": false, - "properties": { - "email": { "type": "string", "description": "Server administrator email given to the FireFox and Chrome push notification services." } - }, - "required": [ "email" ] - }, - "RunOnServerStarted": { "type": "boolean", "default": null, "description": "Execute this when the server startup is completed. The first parameter will be the server version." }, - "RunOnServerUpdated": { "type": "boolean", "default": null, "description": "Execute this when the server has been updated. The first parameter will be the server version." }, - "RunOnServerError": { "type": "boolean", "default": null, "description": "Execute this when the server has to restart due to an error. The first parameter will be the server version." }, - "publicPushNotifications": { "type": "boolean", "default": false, "description": "When true, this server uses MeshCentral.com a push notification relay for Android notifications. Push notifications work even if the Android app is not open." }, - "desktopMultiplex": { "type": "boolean", "default": false, "description": "When true, enabled a server modules that efficiently splits a remote desktop stream to multiple browsers. Also allows slow browsers to not slow down the session for fast ones, this comes at the cost of extra server memory and processing for all remote desktop sessions." }, - "ipBlockedUserRedirect" : { "type": "string", "default": null, "description": "If set, a user from a banned IP address will be redirected to this URL." }, - "userAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "userBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, agents from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "authLog": { "type": "string", "default": null, "description": "File path and name of the authentication log to be created. This log can be parsed by Fail2ban." }, - "InterUserMessaging": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "description": "Users in this list are allowed to send and receive inter-user messages. This can be used to implement bots or other software where MeshCentral is used as data transport. See \"interuser\" websocket command in the code." }, - "manageAllDeviceGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "description": "Users in this list are allowed to see and manage all device groups within their domain." }, - "manageCrossDomain": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "description": "Users in this list are allowed to manage all users in all domains." }, - "localDiscovery": { - "type": "object", - "description": "When this server is in LAN mode, you may discover this server using a multicast discovery tool. When discovery happens, the name and info fields are sent back to the discovery tool.", - "additionalProperties": false, - "properties": { - "name": { "type": "string" }, - "info": { "type": "string" }, - "key": { "type": "string", "description": "When set, encrypts all LAN discovery traffic to agents and tools using this key. This is only useful in LAN/Hybrid mode when agents and tools user multicast to find the server." } - }, - "required": [ "name", "info" ] - }, - "tlsOffload": { "type": [ "boolean", "string" ], "default": false, "description": "When true, indicates that a TLS offloader is in front of the MeshCentral server. More typically, set this to the IP address of the reverse proxy or TLS offloader so that IP forwarding headers will be trusted. For example: \"127.0.0.1,192.168.1.100\"." }, - "trustedProxy": { "type": "string", "default": null, "description": "Trust forwarded headers from these IPs or domains. Providing the magic string \"CloudFlare\" will cause the server to download the IP address list of trusted CloudFlare proxies directly from CloudFlare on each server start. For example: \"127.0.0.1,proxy.example.com,CloudFlare\"." }, - "mpsPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 4433, "description": "The Management Presence Server (MPS), this is the server that received Intel AMT Client Initiated Remote Access (CIRA) connections." }, - "mpsPortBind": { "type": "string", "default": null }, - "mpsAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null }, - "mpsAliasHost": { "type": "string", "default": null }, - "mpsTlsOffload": { "type": "boolean", "default": false, "description": "When set to true, indicate that TLS is being performed by a device in front of MeshCentral." }, - "mpsHighSecurity": { "type": "boolean", "default": false, "description": "When set to true, the MPS server will only accept TLS 1.2 and 1.3 connections. Older Intel AMT devices will not be able to connect." }, - "no2FactorAuth": { "type": "boolean", "default": false }, - "log": { "type": "string", "default": null }, - "syslog": { "type": "string", "default": null }, - "syslogauth": { "type": "string", "default": null }, - "syslogjson": { "type": "string", "default": null }, - "syslogtcp": { "type": "string", "default": null, "description": "Send syslog events over the network (RFC3164) to a target hostname:port. For example: localhost:514" }, - "webrtcConfig": { - "type": "object", - "additionalProperties": false, - "description": "The STUN servers used for WebRTC, if not specified the Google and Mozilla servers and used when the server is not in LAN mode.", - "properties": { - "iceServers": { "type": "array", "uniqueItems": true, "items": { "type": "object", "additionalProperties": false, "properties": { "urls": { "type": "string" } }, "required": [ "urls" ] } } - }, - "required": [ "iceServers" ] - }, - "crowdsec": { - "type": "object", - "additionalProperties": true, - "description": "Enabled the MeshCentral built-in Crowdsec bouncer. This section is passed directly to the bouncer, all of the settings are documented at https://www.npmjs.com/package/@crowdsec/express-bouncer", - "properties": { - "url": { "type": "string", "description": "The URL of your LAPI instance. Ex: http://localhost:8080" }, - "apiKey": { "type": "string", "description": "The bouncer key (generated via cscli)." }, - "fallbackRemediation": { "type": "string", "default": "ban", "enum": ["bypass", "captcha", "ban"], "description": "Action to perform if the CrowdSec agent can't be contacted." } - }, - "required": [ "url", "apiKey" ] - }, - "autoBackup": { - "type": "object", - "properties": { - "mongoDumpPath": { "type": "string" }, - "mysqlDumpPath": { "type": "string" }, - "backupIntervalHours": { "type": "integer" }, - "keepLastDaysBackup": { "type": "integer" }, - "zipPassword": { "type": "string" }, - "backupPath": { "type": "string" }, - "googleDrive": { - "type": "object", - "description": "Enabled automated upload of the server backups to a Google Drive account, once enabled you need to go in \"My Server\" tab as administrator to associate the account.", - "properties": { - "folderName": { - "type": "string", - "default": "MeshCentral-Backups", - "description": "The name of the folder to create in the Google Drive account." - }, - "maxFiles": { - "type": "integer", - "default": null, - "description": "The maximum number of files to keep in the Google Drive folder, older files will be removed if needed." - } - } - }, - "webDAV": { - "type": "object", - "description": "Enabled automated upload of the server backups to a WebDAV account.", - "properties": { - "url": { - "type": "string", - "description": "WebDAV account URL." - }, - "username": { - "type": "string", - "description": "WebDAV account username." - }, - "password": { - "type": "string", - "description": "WebDAV account password." - }, - "folderName": { - "type": "string", - "default": "MeshCentral-Backups", - "description": "The name of the folder to create in the WebDAV account." - }, - "maxFiles": { - "type": "integer", - "default": null, - "description": "The maximum number of files to keep in the WebDAV folder, older files will be removed if needed." - } - } - } - } - }, - "rootCertCommonName" : { "type": "string", "default": "MeshCentralRoot-XXXXXX", "description": "The common name of the MeshCentral server root certificate. By default it's 'MeshCentralRoot-' followed by the first 6 HEX digits of the public key fingerprint. For this setting to take effect, all generated certificates need to be deleted and reset. Existing agents will not be able to connect anymore." }, - "redirects": { "type": "object" }, - "maxInvalidLogin": { - "type": "object", - "additionalProperties": false, - "description": "This section described a policy for how many times an IP address is allowed to attempt to login incorrectly. By default it's 10 times in 10 minutes, but this can be changed here.", - "properties": { - "exclude": { "type": "string", "default": null, "description": "Ranges of IP addresses that are not subject to invalid login limitations. For example: 192.168.1.0/24,172.16.0.1"}, - "time": { "type": "integer", "default": 10, "description": "Time in minutes over which the a maximum number of invalid login attempts is allowed from an IP address." }, - "count": { "type": "integer", "default": 10, "description": "Maximum number of invalid login attempts from an IP address in the time period." }, - "coolofftime": { "type": "integer", "default": null, "description": "Additional time in minute that login attempts will be denied once the invalid login limit is reached." } - } - }, - "maxInvalid2fa": { - "type": "object", - "additionalProperties": false, - "description": "This section described a policy for how many times an IP address is allowed to attempt to perform two-factor authentication (2FA) incorrectly. By default it's 10 times in 10 minutes, but this can be changed here.", - "properties": { - "exclude": { "type": "string", "default": null, "description": "Ranges of IP addresses that are not subject to invalid 2FA limitations. For example: 192.168.1.0/24,172.16.0.1"}, - "time": { "type": "integer", "default": 10, "description": "Time in minutes over which the a maximum number of invalid 2FA attempts is allowed from an IP address." }, - "count": { "type": "integer", "default": 10, "description": "Maximum number of invalid 2FA attempts from an IP address in the time period." }, - "coolofftime": { "type": "integer", "default": null, "description": "Additional time in minute that 2FA attempts will be denied once the invalid 2FA limit is reached." } - } - }, - "amtProvisioningServer": { - "type": "object", - "additionalProperties": false, - "required": [ "deviceGroup", "newMebxPassword", "trustedFqdn", "ip" ], - "description": "When present, this section will enable the Intel AMT provisioning server on the local network. This is used for Intel AMT bare-metal ACM activation.", - "properties": { - "port": { - "type": "number", - "default": 9971, - "description": "Port number that provisioning server will listen to." - }, - "deviceGroup": { - "type": "string", - "description": "The agent-less device group to add Intel AMT devices to once they are activated. Must be of format: mesh/domain/id" - }, - "newMebxPassword": { - "type": "string", - "description": "The MEBX password to set during activation. This password must be at least 8 characters long and have 1 lower, 1 upper, 1 alpha-numeric and 1 non-alpha numeric character." - }, - "trustedFqdn": { - "type": "string", - "description": "The trusted FQDN or provisioning server value the remote device will have. This can be set in MEBx or using the DHCP server option 15 on the local network." - }, - "ip": { - "type": "string", - "description": "The IP address of this server. This address will be used when creating the USB setup.bin file to indicate what IP address to send the hello data to." - } - } - }, - "plugins": { - "type": "object", - "properties": { "enabled": { "type": "boolean" } }, - "required": [ "enabled" ] - } - } - }, - "domaindefaults": { "$ref": "#/properties/domains/items" }, - "domains": { - "type": "object", - "items": { - "type": "object", - "properties": { - "siteStyle": { "type": "integer", "default": 2, "description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages." }, - "title": { "type": "string", "default": "MeshCentral", "description": "The title of this web site. All web pages will have this title." }, - "title2": { "type": "string", "default": null, "description": "Secondary title text that is placed on the upper right on the title on many web pages." }, - "titlePicture": { "type": "string", "default": null, "description": "Web site .png logo file that is 450x66 in size placed in meshcentral-data that is used on the top of many pages." }, - "loginPicture": { "type": "string", "default": null, "description": "Web site .png logo file placed in meshcentral-data that used on the login page when sitestyle is 2." }, - "rootRedirect": { "type": "string", "default": null, "description": "Redirects HTTP root requests to this URL. When in use, direct users to /login to see the normal login page." }, - "mobileSite": { "type": "boolean", "default": true, "description": "When set to false, this setting will disable the mobile site." }, - "maxDeviceView": { "type": "integer", "default": null, "description": "The maximum number of devices a user can see on the devices page at the same time. By default all devices will show, but this may need to be limited on servers with large number of devices." }, - "unknownUserRootRedirect": { "type": "string", "default": null, "description": "Redirects HTTP root requests to this URL only where user is not already logged in. When in use, direct users to /login to see the normal login page." }, - "nightMode": { "type": "integer", "default": 0, "description": "0 = User selects day/night mode, 1 = Always night mode, 2 = Always day mode" }, - "userQuota": { "type": "integer" }, - "meshQuota": { "type": "integer" }, - "loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." }, - "agentKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." }, - "ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." }, - "minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sized web pages." }, - "newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." }, - "newAccountsPass": { "type": "string", "default": null, "description": "When set this password will be required in order to create a new account from the login screen." }, - "newAccountsCaptcha": { "type": "boolean", "default": false, "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "userNameIsEmail": { "type": "boolean", "default": false, "description": "When enabled, the username of each account is also the email address of the account." }, - "newAccountEmailDomains": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "newAccountsRights": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "welcomeText": { "type": "string", "description": "Text that will be shown on the login screen." }, - "welcomePicture": { "type": "string", "description": "Name of the PNG or JPEG file that will be shown on the login screen. Put this file in the meshcentral-data folder and place the file name here." }, - "welcomePictureFullScreen": { "type": "boolean", "default": false, "description": "When enabled, the welcomePicture will show as a fullscreen background on the login screen." }, - "meshMessengerTitle": { "type": "string", "default": "MeshMessenger", "description": "Text that will be displayed on the top of the messenger window when no username or device name is displayed." }, - "meshMessengerPicture": { "type": "string", "default": null, "description": "Name of a .png image file that is placed in meshcentral-data that is displayed on the top of the messenger web page. When null, the default image is displayed." }, - "hide": { "type": "integer", "default": 0, "description": "Sum of: 1 = Hide header, 2 = Hide tab, 4 = Hide footer, 8 = Hide title, 16 = Hide left bar, 32 = Hide back buttons" }, - "footer": { "type": "string", "default": null, "description": "This is a HTML string displayed at the bottom of the web page when a user is logged in." }, - "loginfooter": { "type": "string", "default": null, "description": "This is a HTML string displayed at the bottom of the web page when a user is not logged in." }, - "allowSavingDeviceCredentials": { "type": "boolean", "default": true, "description": "Allow users to save SSH, RDP, VNC device credentials on the server that can be used by any other user." }, - "trustedCert": { "type": "boolean", "default": "This value is normally auto-detected, when set to true, MeshCentral assumes that the TLS certificate comes from a trusted CA and will insure download tools perform certificate checking." }, - "guestDeviceSharing": { - "type": [ "boolean", "object" ], - "default": true, - "description": "When set to false, the desktop/terminal sharing link feature is not available.", - "properties": { - "maxSessionTime": { "type": "number", "description": "When set, limits the maximum length of a guest session, in minutes." } - } - }, - "autoRemoveInactiveDevices": { "type": "integer", "default": 0, "minimum": 0, "maximum": 2000, "description": "Number of days a device can be inactive before it's removed. 0 disables this feature. Device group setting will override this value." }, - "deviceSearchBarServerAndClientName": { "type": "boolean", "default": false, "description": "When set to true, the devices search box will match on both the server name and client name of a device." }, - "agentSelfGuestSharing": { - "type": [ "boolean", "object" ], - "default": false, - "description": "When set to true, MeshCentral Assistant can create it's own guest sharing links.", - "properties": { - "expire": { "type": "number", "description": "When set, limits the self-created guest sharing link to this number of minutes." } - } - }, - "PreconfiguredScripts": { - "type": "array", - "default": null, - "description": "When set, your can try click the run button to run on of these scripts on the remote device.", - "items": { - "type": "object", - "required": [ "name", "type" ], - "properties": { - "name": { - "description": "Name of the script.", - "type": "string" - }, - "type": { - "description": "The type of script.", - "type": "string", - "enum": [ "bat", "ps1", "sh", "agent" ] - }, - "runas": { - "description": "How to run this script, does not apply to agent scripts.", - "type": "string", - "enum": ["agent", "userfirst", "user"] - }, - "cmd": { - "description": "The command or \\r\\n separated commands to run, if set do not use the file key.", - "type": "string" - }, - "file": { - "description": "The script file path and name, if set do not use the cmd key. This file path starts in meshcentral-data.", - "type": "string" - } - } - } - }, - "preConfiguredRemoteInput": { - "type": "array", - "default": null, - "description": "When set, you can right click on the input button in the desktop tab and instantly remotely type one of these pre-configured strings.", - "items": { - "type": "object", - "required": [ "name", "value" ], - "properties": { - "name": { - "description": "Name of the text string.", - "type": "string" - }, - "value": { - "description": "Text string that will be remotely typed when selected.", - "type": "string" - } - } - } - }, - "altMessenging": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string", "description": "Name of the alternative messaging service, for example: \"Jitsi\" " }, - "url": { "type": "string", "description": "URL to the alternative messaging services, for example: \"https://meet.jit.si/myserver-{0}\", for a device {0}, {1}, {2}, {3} is the device id. For a user, {0} is the userid, {1} is full userid with dashes, {2} is real name with no spaces, {3} is real name with dash instead of spaces." }, - "localurl": { "type": "string", "description": "If specified, this is the URL that is used on the administrator side, for example: \"https://meet.jit.si/myserver-{0}\", for a device {0}, {1}, {2}, {3} is the device id. For a user, {0} is the userid, {1} is full userid with dashes, {2} is real name with no spaces, {3} is real name with dash instead of spaces." }, - "type": { "type": "string", "enum": [null, "user", "device"], "default": null, "description": "Indicate if this button should be shown in the user or device type. If omitted, it will be displayed in both." } - }, - "required": [ "name", "url" ] - } - }, - "deviceMeshRouterLinks": { - "rdp": { "type": "boolean", "default": true, "description": "Display a RDP link in the device tab when supported." }, - "ssh": { "type": "boolean", "default": true, "description": "Display a SSH link in the device tab when supported." }, - "scp": { "type": "boolean", "default": true, "description": "Display a SCP link in the device tab when supported." }, - "extralinks": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "required": [ "name", "protocol", "port" ], - "properties": { - "name": { - "description": "Name of the link to be displayed on the web site.", - "type": "string" - }, - "protocol": { - "description": "Protocol. Valid values are: custom,http,https,rdp,ssh,scp,mcrdesktop,mcrfiles.", - "type": "string" - }, - "port": { - "description": "The port on the remote device.", - "default": 0, - "minimum": 0, - "maximum": 65535, - "type": "integer" - }, - "ip": { - "description": "Target IP address. If not specified, the target of the connection is the remote device running the MeshAgent.", - "type": "string" - }, - "localport": { - "description": "The local port MeshCentral Router would bind to. By default, a random available port is used.", - "default": 0, - "minimum": 0, - "maximum": 65535, - "type": "integer" - }, - "filter": { - "description": "Array of node// or mesh// or tag: strings. When set, the link will only show up for the specified devices, device groups or device tag.", - "type": "array", - "items": { "type": "string" } - } - } - } - } - }, - "certUrl": { - "type": "string", - "format": "uri", - "description": "https url when to get the TLS certificate that MeshAgent's will see when connecting to this server. This setting is used when a reverse proxy like NGINX is used in front of MeshCentral." - }, - "myServer": { - "type": [ "object", "boolean" ], - "additionalProperties": false, - "properties": { - "Backup": { "type": "boolean", "default": true, "description": "Allows administrators to backup the server from the My Server tab. This option can only enabled when the NeDB database is in use. For other databases, this option disabled and the setting is ignored." }, - "Restore": { "type": "boolean", "default": true, "description": "Allows administrators to restore the server from the My Server tab. This option can only enabled when the NeDB database is in use. For other databases, this option disabled and the setting is ignored." }, - "Upgrade": { "type": "boolean", "default": true, "description": "Allows administrators to update the server from the My Server tab." }, - "ErrorLog": { "type": "boolean", "default": true, "description": "Allows administrators to see the server crash log the server from the My Server tab." }, - "Console": { "type": "boolean", "default": true, "description": "Allows administrators to access the server console from the My Server tab." }, - "Trace": { "type": "boolean", "default": true, "description": "Allows administrators to access the server trace tab from from the My Server tab." } - } - }, - "passwordRequirements": { - "type": "object", - "properties": { - "min": { "type": "integer", "description": "Minimum number of characters allowed for the account password." }, - "max": { "type": "integer", "description": "Maximum number of characters allowed for the account password." }, - "upper": { "type": "integer", "description": "Minimum number of upper case characters required in the password." }, - "lower": { "type": "integer", "description": "Minimum number of lower case characters required in the password." }, - "numeric": { "type": "integer", "description": "Minimum number of numeric characters required in the password." }, - "nonalpha": { "type": "integer", "description": "Minimum number of non-alpha-numeric characters required in the password." }, - "reset": { "type": "integer", "description": "Number of days after which the user is required to change the account password." }, - "email2factor": { "type": "boolean", "default": true, "description": "Set to false to disable email 2FA." }, - "sms2factor": { "type": "boolean", "default": true, "description": "Set to false to disable SMS 2FA." }, - "push2factor": { "type": "boolean", "default": true, "description": "Set to false to disable push notification 2FA." }, - "otp2factor": { "type": "boolean", "default": true, "description": "Set to false to disable one-time-password 2FA." }, - "backupcode2factor": { "type": "boolean", "default": true, "description": "Set to false to disable 2FA backup codes." }, - "single2factorWarning": { "type": "boolean", "default": true, "description": "Set to false to disable single 2FA warning." }, - "lock2factor": { "type": "boolean", "default": false, "description": "When set to true, prevents any changes to 2FA." }, - "force2factor": { "type": "boolean", "default": false, "description": "Requires that all accounts setup 2FA." }, - "skip2factor": { "type": "string", "description": "IP addresses where 2FA login is skipped, for example: 127.0.0.1,192.168.2.0/24" }, - "oldPasswordBan": { "type": "integer", "description": "Number of old passwords the server should remember and not allow the user to switch back to." }, - "banCommonPasswords": { "type": "boolean", "default": false, "description": "Uses WildLeek to block use of the 10000 most commonly used passwords." }, - "loginTokens": { "type": [ "boolean", "array" ], "default": true, "description": "Allows users to create alternative username/passwords for their account. Set to false to disallow all users, or set to a userid array to only all some users." }, - "twoFactorTimeout": { "type": "integer", "default": 300, "description": "Maximum about of time the to wait for a 2FA token on the login page in seconds." }, - "autofido2fa": { "type": "boolean", "default": false, "description": "If true and user account has FIDO key setup, 2FA login screen will automatically request FIDO 2FA." }, - "maxfidokeys": { "type": "integer", "default": null, "description": "Maximum number of FIDO/YubikeyOTP hardware 2FA keys that can be setup in a user account." }, - "allowaccountreset": { "type": "boolean", "default": true, "description": "If set to false, the account reset option on the login screen will not be available to users." } - } - }, - "twoFactorCookieDurationDays": { "type": "integer", "default": 30, "description": "Number of days that a user is allowed to remember this device for when completing 2FA. Set this to 0 to remove this option." }, - "auth": { "type": "string", "default": null, "enum": [null, "sspi", "ldap"], "description": "Type of user authentication to use, this can be SSPI on Windows or LDAP. If not set, username/password is used." }, - "ldapUserKey": { "type": "string", "default": null, "description": "The LDAP value to use as a user's unique account identifier. Use \"ldapUserKey\" or \"ldapUserBinaryKey\"." }, - "ldapUserBinaryKey": { "type": "string", "default": "objectSid", "description": "The LDAP value to use as a user's unique account identifier, when specified in this field, the values will be HEX converted." }, - "ldapUserName": { "type": "string", "default": "displayName", "description": "The LDAP value to use for the user name, you can also compose the name by setting this value to, for example: \"{{{givenName}}} {{{sn}}}\"" }, - "ldapUserEmail": { "type": "string", "default": "mail", "description": "The LDAP value to use for the user's email address." }, - "ldapUserRealName": { "type": "string", "default": "name", "description": "The LDAP value to use for the user's real name, you can also compose the name by setting this value to, for example: \"{{{givenName}}} {{{sn}}}\"" }, - "ldapUserPhoneNumber": { "type": "string", "default": "telephoneNumber", "description": "The LDAP value to use for the user's phone number." }, - "ldapUserImage": { "type": "string", "default": "thumbnailPhoto", "description": "The LDAP value to use for the user's image." }, - "ldapSaveUserToFile": { "type": "string", "default": null, "description": "When set to a filename, for example c:\\temp\\ldapusers.txt, MeshCentral will save the LDAP user object to this file each time a user logs in. This is used for debugging LDAP issues." }, - "ldapUserGroups": { "type": "string", "default": "memberOf", "description": "The LDAP value to use for the user's group memberships." }, - "ldapSyncWithUserGroups": { - "type": [ "boolean", "object" ], - "default": false, - "description": "When set to true or set to an object, MeshCentral will synchronize LDAP user memberships to MeshCentral user groups.", - "additionalProperties": false, - "properties": { - "filter": { - "type": [ "string", "array" ], - "default": null, - "description": "When set to a string or array of strings, only LDAP membership groups that includes one of the strings will be synchronized with MeshCentral user groups." - } - } - }, - "ldapSiteAdminGroups": { - "type": [ "string", "array" ], - "default": null, - "description": "When set to a list of LDAP groups, users that are part of one of these groups will be set a site administrator, otherwise site administrator rights will be removed." - }, - "ldapUserRequiredGroupMembership": { "type": [ "string", "array" ], "default": null, "description": "A list of LDAP groups. Users must be part of at least one of these groups to allow login. If null, all users are allowed to login." }, - "ldapOptions": { "type": "object", "description": "LDAP options passed to ldapauth-fork" }, - "agentInviteCodes": { "type": "boolean", "default": false, "description": "Enabled a feature where you can set one or more invitation codes in a device group. You can then give a invitation link to users who can use it to download the agent." }, - "agentNoProxy": { "type": "boolean", "default": false, "description": "When enabled, all newly installed MeshAgents will be instructed to no use a HTTP/HTTPS proxy even if one is configured on the remote system" }, - "agentTag": { - "type": "object", - "description": "This section is used to indicate if parts of the meshagent.tag file should be used to set server-side device properties.", - "additionalProperties": false, - "properties": { - "ServerName": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerName:name. 0=Ignore, 1=Set." }, - "ServerDesc": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerDesc:desc. 0=Ignore, 1=Set, 2=SetIfEmpty." }, - "ServerTags": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerTags:tag1,tag2,tag3. 0=Ignore, 1=Set, 2=SetIfEmpty, 3=Append." } - } - }, - "geoLocation": { "type": "boolean", "default": false, "description": "Enables the geo-location feature and device location map in the user interface, this feature is not being worked on." }, - "novnc": { "type": "boolean", "default": true, "description": "When enabled, activates the built-in web-based VNC client." }, - "mstsc": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based RDP client." }, - "ssh": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based SSH client." }, - "webEmailsPath": { "type": "string", "description": "Path where to find custom email templates for this domain." }, - "customUI": { "type": "object" }, - "consentMessages": { - "type": "object", - "description": "This section is used to customize user consent prompts, these show up when asking if a remote session is allowed or not.", - "additionalProperties": false, - "properties": { - "Title": { "type": "string" }, - "Desktop": { "type": "string" }, - "Terminal": { "type": "string" }, - "Files": { "type": "string" }, - "consentTimeout": { "type": "integer", "default": 30, "description": "How long in seconds to show the user consent dialog box." }, - "autoAcceptOnTimeout": { "type": "boolean", "default": false, "description": "If true, user consent is accepted after the timeout." } - } - }, - "notificationMessages": { - "type": "object", - "additionalProperties": false, - "description": "This section is user to customize user notifications when a remote desktop, terminal or file session is connected to a remote system.", - "properties": { - "Title": { "type": "string" }, - "Desktop": { "type": "string" }, - "Terminal": { "type": "string" }, - "Files": { "type": "string" } - } - }, - "agentCustomization": { - "type": "object", - "additionalProperties": false, - "description": "Use this section to customize the agent branding.", - "properties": { - "displayName": { "type": "string", "default": "MeshCentral Agent", "description": "The name of the agent as displayed to the user." }, - "description": { "type": "string", "default": "Mesh Agent background service", "description": "The description of the agent as displayed to the user." }, - "companyName": { "type": "string", "default": "Mesh Agent", "description": "This will be used as the path to install the agent, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's." }, - "serviceName": { "type": "string", "default": "Mesh Agent", "description": "The name of the background service, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's but should be set to an all lower case, no space string." }, - "installText": { "type": "string", "default": null, "description": "Text string to show in the agent installation dialog box." }, - "image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in the MeshCentral Agent installation dialog, image should be square and from 64x64 to 200x200." }, - "fileName": { "type": "string", "default": "meshagent", "description": "The agent filename." }, - "foregroundColor": { "type": "string", "default": null, "description": "Foreground text color, valid values are RBG in format 0,0,0 to 255,255,255 or format #000000 to #FFFFFF." }, - "backgroundColor": { "type": "string", "default": null, "description": "Background color, valid values are RBG in format 0,0,0 to 255,255,255 or format #000000 to #FFFFFF." } - } - }, - "agentFileInfo": { - "type": "object", - "additionalProperties": false, - "description": "Use this section to set resource metadata of the Windows agents prior to signing. In Windows, you can right-click and select properties to view these values.", - "properties": { - "icon": { "type": "string", "description": "Sets the agent icon, this is the name of a .ico file with the file placed in the meshcentral-data folder." }, - "fileDescription": { "type": "string", "description": "Executable file description." }, - "fileVersion": { "type": "string", "description": "Executable file version, in the form of 'n.n.n.n', for example: '1.2.3.4'." }, - "internalName": { "type": "string", "description": "Executable internal name." }, - "legalCopyright": { "type": "string", "description": "Executable legal copyright." }, - "originalFilename": { "type": "string", "description": "Executable original file name." }, - "productName": { "type": "string", "description": "Executable product name." }, - "productVersion": { "type": "string", "description": "Executable product version. Any string format will work, but a alphabetic character is required for this value to show correctly in the Windows property box. For example: 'v1.2.3.4' will work, but '1.2.3.4' will not." } - } - }, - "assistantCustomization": { - "type": "object", - "additionalProperties": false, - "description": "Use this section to customize the MeshCentral Assistant.", - "properties": { - "title": { "type": "string", "default": "MeshCentral Assistant", "description": "Name to show as MeshCentral Assistant dialog title." }, - "image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in MeshCentral Assistant, image should be square and from 64x64 to 128x128." }, - "fileName": { "type": "string", "default": "meshagent", "description": "The MeshCentral Assistant filename." } - } - }, - "androidCustomization": { - "type": "object", - "additionalProperties": false, - "description": "Use this section to customize the MeshCentral Agent for Android.", - "properties": { - "title": { "type": "string", "default": "MeshCentral Agent", "description": "Displayed on top of the MeshCentral Agent for Android." }, - "subtitle": { "type": "string", "default": null, "description": "Subtitle displayed until the title on the toolbar." }, - "image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in MeshCentral Agent for Android, image should be square and from 64x64 to 128x128." } - } - }, - "ipBlockedUserRedirect" : { "type": "string", "default": null, "description": "If set, a user from a banned IP address will be redirected to this URL." }, - "userRequiredHttpHeader": { "type": "object", "default": null, "description": "When set, requires that a browser request have set HTTP header to allow user login. Example: \"{ \"Sec-Fetch-Dest\": \"iframe\" }\"" }, - "userAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "userBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, agents from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "userSessionIdleTimeout": { "type": "integer", "default": null, "description": "When set, idle users will be disconnected after a set amounts of minutes." }, - "userConsentFlags": { - "type": "object", - "additionalProperties": false, - "description": "Use this section to require user consent for this domain.", - "properties": { - "desktopnotify": { "type": "boolean", "default": false, "description": "Enable desktop notification for this domain." }, - "terminalnotify": { "type": "boolean", "default": false, "description": "Enable terminal notification for this domain." }, - "filenotify": { "type": "boolean", "default": false, "description": "Enable files notification for this domain." }, - "desktopprompt": { "type": "boolean", "default": false, "description": "Enable desktop prompt for this domain." }, - "terminalprompt": { "type": "boolean", "default": false, "description": "Enable terminal user prompt for this domain." }, - "fileprompt": { "type": "boolean", "default": false, "description": "Enable files prompt for this domain." }, - "desktopprivacybar": { "type": "boolean", "default": false, "description": "Enable remote desktop privacy bar for this domain." } - } - }, - "urlSwitching": { "type": "boolean", "default": true, "description": "When users navigate thru the web interface, the URL on top will change to point to the current screen. This allows a user to refresh or bookmark the URL and come back to the correct screen. Setting false here will disable this feature." }, - "desktopPrivacyBarText": { "type": "string", "description": "This is the text that will be shown in the remote desktop privacy bar. You can use {0} to display the account realname or {1} to display the account identifier in the string." }, - "limits": { - "type": "object", - "additionalProperties": false, - "properties": { - "MaxDevices": { "type": "integer", "default": null, "description": "Maximum number of devices in this domain." }, - "MaxUserAccounts": { "type": "integer", "default": null, "description": "Maximum number of devices in this domain." }, - "MaxUserSessions": { "type": "integer", "default": null, "description": "Maximum number of user sessions that can connect to this server for this domain." }, - "MaxAgentSessions": { "type": "integer", "default": null, "description": "Maximum number of agents that can connect to this server for this domain." }, - "MaxSingleUserSessions": { "type": "integer", "default": null, "description": "Maximum number of sessions a single user can have. Each time a user opens a new browser tab or opens a new browser on a different computer, a new user session is created." } - } - }, - "files": { - "type": "object", - "description": "Values that affect the files feature", - "properties": { - "sftpConnect" : { "type": "boolean", "default": true, "description": "When false, removes the 'SFTP Connect' button from the files tab unless this is the only possible option." } - } - }, - "terminal": { - "type": "object", - "description": "Values that affect the terminal feature", - "properties": { - "sshConnect" : { "type": "boolean", "default": true, "description": "When false, removes the 'SSH Connect' button from the terminal tab unless this is the only possible option." }, - "linuxShell": { - "type": "string", - "enum": [ "any", "root", "user", "login" ], - "default": "any", - "description": "Indicate what terminal options are available when the user clicks the right mouse button on the terminal connect button." - }, - "launchCommand": { - "type": "object", - "description": "Indicate what string the agent must write to the shell after starting a terminal session", - "linux": { "type": "string", "default": " alias ls=\\'ls --color=auto\\';clear\\n", "description": "String to write after opening a Linux terminal." }, - "darwin": { "type": "string", "default": null, "description": "String to write after opening a macOS terminal." }, - "freebsd": { "type": "string", "default": null, "description": "String to write after opening a FreeBSD terminal." } - } - } - }, - "desktop": { - "type": "object", - "description": "Values that affect the desktop feature", - "properties": { - "viewonly": { - "type": "boolean", - "description": "When set to true, the remote desktop feature is view only.", - "default": "false" - } - } - }, - "amtScanOptions": { - "description": "List of local network Intel AMT scanning options offered in the user interface. For example [\"LabNetwork 192.168.15.0/23\", \"SalesNetwork 192.168.8.0/24\"].", - "type": "array", - "default": null, - "items": { "type": "string" } - }, - "amtManager": { - "type": "object", - "additionalProperties": false, - "description": "Information passed to the AMT manager module that impacts all Intel AMT device managed within this domain.", - "properties": { - "TlsConnections": { "type": "boolean", "default": true, "description": "When set to false, MeshCentral will use TLS to connect to Intel AMT, this is not recommended." }, - "TlsAcmActivation": { "type": "boolean", "default": false, "description": "When set to false, MeshCentral will not attempt a TLS ACM activation on Intel AMT v14+" }, - "AdminAccounts": { - "description": "List of username and passwords to try when connecting to Intel AMT.", - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "required": [ "pass" ], - "properties": { - "user": { - "description": "Intel AMT administrator username.", - "type": "string", - "default": "admin" - }, - "pass": { - "description": "Intel AMT administrator password.", - "type": "string" - } - } - } - }, - "EnvironmentDetection": { - "description": "List of up to 4 domain suffixes to configure in Intel AMT when activating CIRA.", - "type": "array", - "items": { - "type": "string", - "minItems": 1, - "maxItems": 4, - "uniqueItems": true - } - }, - "TlsRootCert": { - "description": "Specifies a certificate and private key to use to issue Intel AMT TLS certificates. By default the MeshCentral self-signed root certificate is used.", - "type": "object", - "properties": { - "certpfx": { - "description": "Name of the certificate file that is in .p12 or .pfx format in meshcentral-data, use this with certpfxpass.", - "type": "string" - }, - "certpfxpass": { - "description": "Password for the file specified in certpfx.", - "type": "string" - }, - "certfile": { - "description": "Name of the certificate file in PEM format located in meshcentral-data. Using this with keyfile.", - "type": "string" - }, - "keyfile": { - "description": "Name of the private key file in PEM format located in meshcentral-data. Using this with certfile.", - "type": "string" - } - } - }, - "WifiProfiles": { - "description": "List of WIFI profiles to setup in any managed Intel AMT device with a WIFI network interface.", - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "required": [ "ssid" ], - "properties": { - "name": { - "description": "WIFI profile name, if not specified the SSID is used.", - "type": "string" - }, - "ssid": { - "description": "SSID of the WIFI station.", - "type": "string" - }, - "authentication": { - "description": "WIFI authentication.", - "type": "string", - "enum": [ "wpa-psk", "wpa2-psk", "wpa-8021x", "wpa2-802.1x", "wpa3-sae-802.1x", "wpa3-owe-802.1x" ], - "default": "wpa2-psk" - }, - "encryption": { - "description": "WIFI encryption.", - "type": "string", - "enum": [ "ccmp-aes", "tkip-rc4" ], - "default": "ccmp-aes" - }, - "password": { - "description": "Password on the WIFI station", - "type": "string", - "minLength": 8, - "maxLength": 63 - }, - "802.1x": { - "description": "802.1x settings for this WIFI profile. Only required if the WIFI authentication type has 802.1x", - "default": null, - "type": "object", - "additionalProperties": false, - "required": [ "authenticationProtocol" ], - "properties": { - "authenticationProtocol": { - "description": "Identifies the authentication protocol used to authenticate the access requestor to the AAA server.", - "type": [ "integer", "string" ], - "enum": [ "EAP-TLS", "EAP-TTLS/MSCHAPv2", "PEAPv0/EAP-MSCHAPv2", "PEAPv1/EAP-GTC", "EAP-FAST/MSCHAPv2", "EAP-FAST/GTC", "EAP-MD5", "EAP-PSK", "EAP-SIM", "EAP-AKA", "EAP-FAST/TLS", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] - }, - "serverCertificateNameComparison": { - "type": [ "integer", "string" ], - "default": "FullName", - "description": "Determines the comparison algorithm used between the ServerCertificateName value and the subject name field of the certificate presented by the AAA server.", - "enum": [ "FullName", "DomainSuffix", 2, 3 ] - }, - "serverCertificateName": { - "type": "string", - "default": null, - "description": "The name compared against the subject name field in the certificate provided by the AAA server.", - "maxLength": 80 - }, - "availableInS0": { - "type": "boolean", - "default": true, - "description": "Indicates the activity setting of the 802.1X module in H0 state" - }, - "protectedAccessCredentialHex": { - "type": "string", - "default": null, - "description": "A credential used by the supplicant and AAA server to establish a mutually authenticated encrypted tunnel for confidential user authentication.", - "maxLength": 64 - }, - "pacPassword": { - "type": "string", - "default": null, - "description": "Optional password to extract the PAC (Protected Access Credential) information from the PAC data.", - "maxLength": 256 - }, - "domain": { - "type": "string", - "default": null, - "description": "The domain within which Username is unique.", - "maxLength": 128 - }, - "username": { - "type": "string", - "default": null, - "description": "Within the domain specified by Domain, Identifies the user that is requesting access to the network.", - "maxLength": 128 - }, - "password": { - "type": "string", - "default": null, - "description": "The password associated with the user identified by Username and Domain.", - "maxLength": 32 - }, - "roamingIdentity": { - "type": "string", - "default": null, - "description": "A string presented to the authentication server in 802.1x protocol exchange", - "maxLength": 80 - }, - "pxeTimeoutInSeconds": { - "type": "integer", - "default": 120, - "description": "Timeout in seconds, in which the Intel(R) AMT will hold an authenticated 802.1X session." - } - } - } - } - } - }, - "802.1x": { - "description": "802.1x settings for the Intel AMT Wired interface. If set to false, any existing 802.1x wired profile will be removed from Intel AMT.", - "default": null, - "type": [ "object", "boolean" ], - "additionalProperties": false, - "required": [ "authenticationProtocol" ], - "properties": { - "authenticationProtocol": { - "description": "Identifies the authentication protocol used to authenticate the access requestor to the AAA server.", - "type": [ "integer", "string" ], - "enum": [ "EAP-TLS", "EAP-TTLS/MSCHAPv2", "PEAPv0/EAP-MSCHAPv2", "PEAPv1/EAP-GTC", "EAP-FAST/MSCHAPv2", "EAP-FAST/GTC", "EAP-MD5", "EAP-PSK", "EAP-SIM", "EAP-AKA", "EAP-FAST/TLS", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] - }, - "serverCertificateNameComparison": { - "type": [ "integer", "string" ], - "description": "Determines the comparison algorithm used between the ServerCertificateName value and the subject name field of the certificate presented by the AAA server.", - "enum": [ "FullName", "DomainSuffix", 2, 3 ] - }, - "serverCertificateName": { - "type": "string", - "default": null, - "description": "The name compared against the subject name field in the certificate provided by the AAA server.", - "maxLength": 80 - }, - "availableInS0": { - "type": "boolean", - "default": true, - "description": "Indicates the activity setting of the 802.1X module in H0 state" - }, - "protectedAccessCredentialHex": { - "type": "string", - "default": null, - "description": "A credential used by the supplicant and AAA server to establish a mutually authenticated encrypted tunnel for confidential user authentication.", - "maxLength": 64 - }, - "pacPassword": { - "type": "string", - "default": null, - "description": "Optional password to extract the PAC (Protected Access Credential) information from the PAC data.", - "maxLength": 256 - }, - "domain": { - "type": "string", - "default": null, - "description": "The domain within which Username is unique.", - "maxLength": 128 - }, - "username": { - "type": "string", - "default": null, - "description": "Within the domain specified by Domain, Identifies the user that is requesting access to the network.", - "maxLength": 128 - }, - "password": { - "type": "string", - "default": null, - "description": "The password associated with the user identified by Username and Domain.", - "maxLength": 32 - }, - "roamingIdentity": { - "type": "string", - "default": null, - "description": "A string presented to the authentication server in 802.1x protocol exchange", - "maxLength": 80 - }, - "pxeTimeoutInSeconds": { - "type": "integer", - "default": 120, - "description": "Timeout in seconds, in which the Intel(R) AMT will hold an authenticated 802.1X session." - } - } - } - } - }, - "amtAcmActivation": { - "type": "object", - "additionalProperties": false, - "properties": { - "log": { "type": "string" }, - "strictCommonName": { "type": "boolean", "default": false, "description": "When set to true, the certificate common name needs to match exactly the Intel AMT trusted FQDN or DHCP Option 15. If false, some flexibility may be given to the matching." }, - "certs": { - "type": "object", - "additionalProperties": { - "type": "object", - "additionalProperties": false, - "properties": { - "certfiles": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "keyfile": { "type": "string" } - }, - "required": [ "certfiles", "keyfile" ] - } - } - }, - "required": [ "certs" ] - }, - "redirects": { - "type": "object", - "additionalProperties": { "type": "string" }, - "description": "This is used to create HTTP redirections. For example setting \"redirects\": { \"example\":\"https://example.com\" } will make it so that anyone accessing /example on the server will get redirected to the specified URL." - }, - "yubikey": { - "type": "object", - "additionalProperties": false, - "properties": { - "id": { "type": "string" }, - "secret": { "type": "string" }, - "proxy": { "type": "string", "format": "uri" } - }, - "required": [ "id", "secret" ] - }, - "httpHeaders": { "type": "object", "additionalProperties": { "type": "string" } }, - "agentConfig": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "default": null, "description": "Key and values to add to the MeshAgent .msh file" }, - "assistantConfig": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "default": null, "description": "Key and values to add to the MeshCentral Assistant .msh file" }, - "clipboardGet": { "type": "boolean", "default": true, "description": "When false, users can't set the clipboard of a remove device." }, - "clipboardSet": { "type": "boolean", "default": true, "description": "When false, users can't get the clipboard of a remove device." }, - "localSessionRecording": { "type": "boolean", "default": true, "description": "When false, removes the local recording feature on remote desktop." }, - "sessionRecording": { - "type": "object", - "additionalProperties": false, - "properties": { - "onlySelectedUsers": { "type": "boolean", "default": false, "description": "When enabled, only device users with the session recording feature turned on will be recorded. When false, all users are recorded." }, - "onlySelectedUserGroups": { "type": "boolean", "default": false, "description": "When enabled, only device user groups with the session recording feature turned on will be recorded. When false, all users are recorded." }, - "onlySelectedDeviceGroups": { "type": "boolean", "default": false, "description": "When enabled, only device groups with the session recording feature turned on will be recorded. When false, all devices are recorded." }, - "filepath": { "type": "string", "description": "The file path where recording files are kept." }, - "index": { "type": "boolean", "default": false, "description": "If true, automatically index remote desktop recordings so that the plays can skip to any place in the file." }, - "maxRecordings": { "type": "integer", "default": null, "description": "Maximum number of recording files to keep." }, - "maxRecordingDays": { "type": "integer", "default": null, "description": "Maximum number of days to keep a recording." }, - "maxRecordingSizeMegabytes": { "type": "integer", "default": null, "description": "Maximum number of recordings in megabytes. Once exceed, remove the oldest recordings." }, - "protocols": { "type": "array", "uniqueItems": true, "items": { "type": "integer" }, "description": "This is an array: 1 = Terminal, 2 = Desktop, 5 = Files, 100 = Intel AMT WSMAN, 101 = Intel AMT Redirection, 200 = Messenger" } - }, - "required": [ "protocols" ] - }, - "showPasswordLogin": { "type": "boolean", "default": true, "description": "When set to false, hides the username and password prompt on login screen." }, - "sendgrid": { - "title" : "SendGrid.com Email server", - "description": "Connects MeshCentral to the SendGrid email server, allows MeshCentral to send email messages for 2FA or user notification.", - "type": "object", - "properties": { - "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "apikey": { "type": "string", "description": "The SendGrid API key." }, - "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." } - }, - "required": [ "from", "apikey" ] - }, - "smtp": { - "title" : "SMTP email server", - "description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.", - "type": "object", - "properties": { - "name": { - "type": "string", - "format": "hostname", - "description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays." - }, - "host": { - "type": "string", - "format": "hostname", - "description": "Hostname of the SMTP server." - }, - "port": { - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "SMTP server port number." - }, - "from": { - "type": "string", - "format": "email", - "description": "Email address used in the messages from field." - }, - "tls": { "type": "boolean" }, - "auth": { - "type": "object", - "properties": { - "clientId": { "type": "string" }, - "clientSecret": { "type": "string" }, - "refreshToken": { "type": "string" } - }, - "required": [ "clientId", "clientSecret", "refreshToken" ] - }, - "tlscertcheck": { "type": "boolean" }, - "tlsstrict": { "type": "boolean" }, - "verifyemail": { - "type": "boolean", - "default": true, - "description": "When set to false, the email format and DNS MX record are not checked." - } - }, - "required": [ "from" ] - }, - "sendmail": { - "title" : "Send email using the sendmail command", - "description": "Makes MeshCentral send emails using the Unix sendmail command. Allows MeshCentral to send email messages for 2FA or user notification.", - "type": "object", - "properties": { - "newline": { "type": "string", "default": "unix", "description": "Possible values are unix or windows" }, - "path": { "type": "string", "default": "sendmail", "description": "Path to the sendmail command" }, - "args": { "type": "array", "items": { "type": "string" }, "default": null, "description": "Array or arguments to pass to sendmail" } - } - }, - "authStrategies": { - "type": "object", - "additionalProperties": false, - "properties": { - "twitter": { - "type": "object", - "additionalProperties": false, - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "clientid", "clientsecret" ] - }, - "google": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "clientid", "clientsecret" ] - }, - "github": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "clientid", "clientsecret" ] - }, - "reddit": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "clientid", "clientsecret" ] - }, - "azure": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "tenantid": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "clientid", "clientsecret", "tenantid" ] - }, - "jumpcloud": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "entityid": { "type": "string" }, - "idpurl": { "type": "string", "format": "uri" }, - "cert": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "entityid", "idpurl", "cert" ] - }, - "saml": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "disableRequestedAuthnContext": { "type": "boolean" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "newAccountsRights": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "entityid": { "type": "string" }, - "idpurl": { "type": "string", "format": "uri" }, - "cert": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "entityid", "idpurl", "cert" ] - }, - "oidc": { - "type": "object", - "properties": { - "authorizationURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the authorization URL. (If set tokenURL and userInfoURL need set also)" }, - "callbackURL": { "type": "string", "format": "uri", "description": "Required, this is the URL that your SSO provider sends auth approval to." }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "issuer": { "type": "string", "format": "uri", "description": "Full URL of SSO portal" }, - "tokenURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the token URL. (If set authorizationURL and userInfoURL need set also)" }, - "userInfoURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the user info URL. (If set authorizationURL and tokenURL need set also)" }, - "logouturl": { "type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link." }, - "newAccounts": { "type": "boolean", "default": true }, - "groups": { - "type": "object", - "properties": { - "required": { "type": [ "string", "array" ], "description": "When set, the user must be part of one of the OIDC user groups to login to MeshCentral." }, - "siteadmin": { "type": [ "string", "array" ], "description": "When set, users part of these groups will be promoted with site administrator in MeshCentral, users that are not part of these groups will be demoted." }, - "sync": { - "type": [ "boolean", "object" ], - "description": "Allows some or all ODIC user groups to be mirrored within MeshCentral as user groups.", - "properties": { - "enabled": { "type": "boolean", "default": false }, - "filter": { "type": [ "string", "array" ], "description": "When set, limits what OIDC groups are mirrored into MeshCentral user groups." } - } - } - } - } - }, - "required": [ "issuer", "clientid", "clientsecret", "callbackURL" ] - } - } - } - } - } - }, - "letsEncrypt": { - "title" : "Built-in Let's Encrypt support", - "description": "If your server has a proper DNS name and it public facing on the Internet with a public facing HTTP server on port 80, you can get a free TLS certificate.", - "type": "object", - "additionalProperties": false, - "properties": { - "email": { "type": "string", "format": "email", "description": "Email address of the administrator of this server. Make sure this is a valid email address otherwise the certificate request will fail." }, - "names": { "type": "string" }, - "skipChallengeVerification": { "type": "boolean", "default": false, "description": "By default, MeshCentral will perform a self-test to make sure HTTP port 80 can respond correctly before making a request to Let's Encrypt. In some cases, this self-test can't work and must be skipped." }, - "production": { "type": "boolean", "default": false, "description": "By default a test certificate will be obtained from Let's Encrypt. Always start by getting a test certificate and make sure that works before setting this to true and obtaining a production certificate. Making too many bad requests for a production certificate will get you banned for a long period of time." } - }, - "required": [ "email", "names" ] - }, - "peers": { - "title" : "Server peering", - "description": "Setup peer server for load-balancing between many servers.", - "type": "object", - "minProperties": 1, - "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, - "additionalProperties": false, - "properties": { - "serverId": { "type": "string" }, - "servers": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { "url": { "type": "string", "format": "uri" } }, - "required": [ "url" ] - } - } - }, - "required": [ "serverId", "servers" ] - }, - "sendgrid": { - "title" : "SendGrid.com Email server", - "description": "Connects MeshCentral to the SendGrid email server, allows MeshCentral to send email messages for 2FA or user notification.", - "type": "object", - "properties": { - "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "apikey": { "type": "string", "description": "The SendGrid API key." }, - "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." } - }, - "required": [ "from", "apikey" ] - }, - "smtp": { - "title" : "SMTP email server", - "description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.", - "type": "object", - "properties": { - "host": { "type": "string", "format": "hostname" }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "tls": { "type": "boolean" }, - "tlscertcheck": { "type": "boolean" }, - "tlsstrict": { "type": "boolean" }, - "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." } - }, - "required": [ "host", "port", "from", "tls" ] - }, - "sms": { - "title" : "SMS provider", - "description": "Connects MeshCentral to a SMS text messaging provider, allows MeshCentral to send SMS messages for 2FA or user notification.", - "oneOf": [ - { - "type": "object", - "properties": { - "provider": { "type": "string", "enum": [ "twilio" ] }, - "sid": { "type": "string" }, - "auth": { "type": "string" }, - "from": { "type": "string" } - }, - "required": [ "provider", "sid", "auth", "from" ] - }, - { - "type": "object", - "properties": { - "provider": { "type": "string", "enum": [ "plivo" ] }, - "id": { "type": "string" }, - "token": { "type": "string" }, - "from": { "type": "string" } - }, - "required": [ "provider", "id", "token", "from" ] - }, - { - "type": "object", - "properties": { - "provider": { "type": "string", "enum": [ "telnyx" ] }, - "apikey": { "type": "string" }, - "from": { "type": "string" } - }, - "required": [ "provider", "apikey", "from" ] - }, - { - "type": "object", - "properties": { - "provider": { "type": "string", "enum": [ "url" ] }, - "url": { "type": "string", "description": "A http or https URL with {{phone}} and {{message}} in the string. These will be replaced with the URL encoded target phone number and message." } - }, - "required": [ "url" ] - } - ] - } - }, - "required": [ "settings", "domains" ] -} -``` \ No newline at end of file +* DNS +* HTTPS +* MPS (Management Presence Server) +* MongoDB +* MariaDB +* SQLite3 +* MySQL +* PostgreSQL +* AceBase +* WAN (Wide Area Network) +* LAN (Local Area Network) +* Maintenance Mode +* Session Cookie +* Database Encryption +* Web Relay +* Agent Connection +* TLS (Transport Layer Security) +* WebRTC +* Web Push Notifications +* Auto Backup +* Crowdsec +* IP KVM (Keyboard, Video, Mouse over IP) +* Mesh Router +* Syslog +* WebDAV +* Certificates and Authentication +* MeshCentral Server Settings +* Device Management +* User Permissions +* Remote Desktop Configuration + +and more! + +![Server Options]() + +![Domain Options]() \ No newline at end of file diff --git a/docs/docs/meshcentral/customization.md b/docs/docs/meshcentral/customization.md new file mode 100644 index 00000000..654bb0bf --- /dev/null +++ b/docs/docs/meshcentral/customization.md @@ -0,0 +1,105 @@ +# Customization + +Whitelabeling your MeshCentral installation to personalize it to your company's brand, as well as having your own terms of use is one of the first things many people do after installation. + +
+ +
+ +## Web Branding + +You can put your own logo on the top of the web page. To get started, get the file “logoback.png” from the folder “node_modules/meshcentral/public/images” and copy it to your “meshcentral-data” folder. In this example, we will change the name of the file “logoback.png” to “title-mycompany.png”. Then use any image editor to change the image and place your logo. + +![](images/2022-05-19-00-38-51.png) + +Once done, edit the config.json file and set one or all of the following values: + +```json +"domains": { + "": { + "Title": "", + "Title2": "", + "TitlePicture": "title-sample.png", + "loginPicture": "logintitle-sample.png", + "welcomeText": "This is sample text", + "welcomePicture": "mainwelcome-04.jpg", + "welcomePictureFullScreen": true, + "siteStyle": "1", + "nightMode": "1", + "meshMessengerTitle": "Mesh Chat", + "meshMessengerPicture": "chatimage.png", + "footer": "This is a HTML string displayed at the bottom of the web page when a user is logged in.", + "loginfooter": "This is a HTML string displayed at the bottom of the web page when a user is not logged in." + }, +``` + +This will set the title and sub-title text to empty and set the background image to the new title picture file. You can now restart the server and take a look at the web page. Both the desktop and mobile sites will change. + +![](images/2022-05-19-00-39-35.png) + +![](images/2022-05-19-00-39-42.png) + +The title image must a PNG image of size 450 x 66. + +You can also customize the server icon in the “My Server” tab. By default, it’s a picture of a desktop with a padlock. + +![](images/2022-05-19-00-40-00.png) + +If, for example, MeshCentral is running on a Raspberry Pi. You may want to put a different picture at this location. Just put a “server.jpg” file that is 200 x 200 pixels in the “meshcentral-data” folder. The time MeshCentral page is loaded, you will see the new image. + +![](images/2022-05-19-00-40-13.png) + +This is great to personalize the look of the server within the web site. + +### Customizing Web Icons +MeshCentral lets you change the icons for different devices shown in the Web User Interface. To do this the proper way, you should make a new folder called `meshcentral-web` in the main directory, where you find other folders like `meshcentral-data`, `meshcentral-backup`, `meshcentral-files`, and `node-modules`. Inside `meshcentral-web`, make another folder named `public` and copy the entire `node_modules/meshcentral/public/images` folder into this new `meshcentral-web/public` folder and then edit the files in `meshcentral-web/public/images/`. This step is suggested because if MeshCentral updates, it might delete any changes in `node_modules`. But, changes in `meshcentral-web` will stay safe, and MeshCentral will use these files instead of the originals in `node_modules`. + +To update device icons, you need to edit these files: `meshcentral-web/public/images/webp/iconsXX.webp` (`icons16.webp`, `icons32.webp`, `icons50.webp`, `icons100.webp`), and `meshcentral-web/public/images/iconsXX.png` (`icons16.png`, `icons32.png`, `icons50.png`, `icons64.png`, `icons100.png`) and the corresponding `meshcentral-web/public/images/icons256-X-1.png`. Make sure to keep the resolution of these files as it is. + +By following these steps, you can customize any icon in MeshCentral. Just find and change the corresponding image files in the `meshcentral-web/public/images` folder. Similarly, you can also move other folders from `node_modules/meshcentral` to `meshcentral-web` while keeping the original folder structure. This allows you to modify other parts of MeshCentral too, like the `.handlebars` templates for the web interface. Simply copy files from `node_modules/meshcentral/views` to `meshcentral-web/views` and make your changes in `meshcentral-web`. This lets you match MeshCentral's look to your company's brand or your own style. +![](images/custom-web-icons.png) + +### Customizing Agent Invitation +Agents can be invited by public link or via email. [Click Here](assistant.md#agent-invitation) to see details. + +## Agent Branding + +You can customize the Agent to add your own logo, change the title bar, install text, the service name, or even colors! + +!!!note + The Customization must be done FIRST and BEFORE you deploy your agents! Once the agents have been deployed, any customization made afterwards, will not sync! This is because the setup files are customized on the fly, then when you install the agents, the exe and .msh file with the customizations in are copied over to the required folder, so you will need to reinstall the agent for agent customizations to take effect. + +![](images/2022-08-24-06-42-40.png) + +```json +"domains": { + "": { + "agentCustomization": { + "displayName": "MeshCentral Agent", + "description": "Mesh Agent background service", + "companyName": "Mesh Agent Company", + "serviceName": "Mesh Agent Service", + "installText": "Text string to show in the agent installation dialog box", + "image": "mylogo.png", + "fileName": "meshagent", + "foregroundColor": "#FFA500", + "backgroundColor": "#EE82EE" + } + } +} +``` + +![agent icon](images/agentico.png) + +## Terms of use + +You can change the terms of use of the web site by adding a “terms.txt” file in the “meshcentral-data” folder. The file can include HTML markup. Once set, the server does not need to be restarted, the updated terms.txt file will get used the next time it’s requested. + +For example, placing this in “terms.txt” + +``` +
+This is a test file. +``` + +Will show this on the terms of use web page. diff --git a/docs/docs/meshcentral/debugging.md b/docs/docs/meshcentral/debugging.md index 339e4f53..68a3725e 100644 --- a/docs/docs/meshcentral/debugging.md +++ b/docs/docs/meshcentral/debugging.md @@ -23,7 +23,7 @@ Make sure you understand how MeshCentral works with your browser using chrome de ### Understanding node and paths -Note that when running MeshCentral, you should always run like from the path that is parent to node_modules, so you do this: +Note that when running MeshCentral, you should always run from the path that is parent to node_modules, so you do this: ``` cd C:\Program Files\Open Source\MeshCentral @@ -39,7 +39,7 @@ node meshcentral The problem with the second command is that NPM may install missing modules in the incorrect location. -Also, in general I recommend not using the MeshCentral MSI Installer and just install manually unless you are very much scared of the command prompt. Anyone that knows about bit about the shell should install MeshCentral like this: +Also, in general I recommend not using the MeshCentral MSI Installer and just install manually unless you are very scared of the command prompt. Anyone that knows a bit about the shell should install MeshCentral like this: ``` mkdir c:\meshcentral @@ -50,11 +50,11 @@ node node_modules\meshcentral node node_modules\meshcentral --install ``` -This way, just have a lot more control over what is going on. Just my opinion, the MSI installer basically does the same thing and installs NodeJS for you. +This way, you have a lot more control over what is going on. In my opinion, the MSI installer basically does the same thing and installs NodeJS for you. ### Unable to update server -Generally the problem is that MeshCentral can't find the npm tool and so, can't run it to see if there is a new version. You can fix this by setting the path to npm in the config.json like this: +Generally the problem is that MeshCentral can't find the npm tool and therefore, can't run it to see if there is a new version. You can fix this by setting the path to npm in the config.json like this: ```json { @@ -86,14 +86,59 @@ node node_modules/meshcentral --stop ### Port Troubleshooting on server -If you're getting a `port 4433 is not available` error, this is because someone else is using this port, very likely another instance of MeshCentral. If your MeshCentral server is bound to ports 81/444 MeshCentral could not get port 80/443 and got the next available ones. +If you're getting a `port 4433 is not available` error, this is because another process is using this port, very likely another instance of MeshCentral. If your MeshCentral server is bound to ports 81/444 MeshCentral could not get port 80/443 and got the next available ones. In general the problem is that you are running two MeshCentral instances at the same time. Probably one as a background Windows Service and one in the command line. Which ever instance can grab port 4433 will have a running MPS and CIRA should work, but the second instance will not have port 4433 and CIRA will not work. +### Running Meshcentral server in debug mode + +Debug more will cause MeshCentral to output a lot of debug messages to the console. To display all debug messages, run MeshCentral like this: + +```bash +node node_modules/meshcentral --debug +``` + +A more practical way to run the debug command it to specify what messages you want printed out using a comma seperated list, for example: + +```bash +node node_modules/meshcentral --debug web,amt,mps +``` + +Here is the list of all debug options: + +``` +cookie - Cookie encoder +dispatch - Message Dispatcher +main - Main Server Messages +peer - MeshCentral Server Peering +agent - MeshAgent traffic +agentupdate - MeshAgent update +cert - Server Certificate +db - Server Database +email - Email/SMS/Push Traffic +web - Web Server +webrequest - Web Server Requests +relay - Web Socket Relay +httpheaders - Web Server HTTP Headers +authlog - User Authentication Log +amt - Intel AMT +webrelay - Connection Relay +mps - CIRA Server +mpscmd - CIRA Server Commands +``` + +You can also specify the `debug` option in the config.json file in the `settings` section. For example: + +``` +"settings": { + "debug": "web,amt,mps" +} +``` + + ### Enabling trace in your browser Dev Tools -`Trace=1` as a parameter in chrome dev tools for debugging - +You can enable browser console tracing by adding `trace=1` as a parameter to the URL of the MeshCentral main web page. For example `https://myserver.com/?trace=1`. Once present, open the browser's console window to see all web client tracing messages. To log all database queries, change log_statement in /etc/postgresql/13/main/postgresql.conf diff --git a/docs/docs/meshcentral/devicetabs.md b/docs/docs/meshcentral/devicetabs.md index 0ae26c80..8e4f4169 100644 --- a/docs/docs/meshcentral/devicetabs.md +++ b/docs/docs/meshcentral/devicetabs.md @@ -54,10 +54,11 @@ Chat Legend -* **_Black color_**: Device is powered on (Intel AMT & agents) -* **_Purple color_**: Device is in sleep state (Intel AMT agents only) -* **_Teal color_**: Device is connected through AMT/CIRA, but not powered on (Intel AMT agents only) -* **_Grey color_**: Device is powered off (Intel AMT & agents) +* **_Black color_**: Device is Powered On on (Intel AMT & agents) +* **_Purple color_**: Device is in sleep state such as Hibernating (Intel AMT agents only) +* **_Teal color_**: Device is connected through AMT/CIRA, but the Power State is UNKNOWN (Intel AMT agents only) +* **_DarkGreen color_**: Device is connected through AMT/CIRA and is in Soft-Off Power State (Intel AMT agents only) +* **_Grey color_**: Device is Powered Off/Not Connected To MeshCentral (Intel AMT & agents) ### Text Links @@ -210,3 +211,60 @@ Note you can show CPU and Memory usage info by clicking the icon in the top righ For debugging and communicating with the mesh agent. It allows JS commands to be issued to the device but also run extra commands from the meshcore. Type `help` for all available options + +- 2falock +- acceleratorsstats +- agentissues +- agentstats +- amtacm +- amtmanager +- amtpasswords +- amtstats +- args +- autobackup +- backupconfig +- bad2fa +- badlogins +- certexpire +- certhashes +- closeusersessions +- cores +- dbcounters +- dbstats +- dispatchtable +- dropallcira +- dupagents +- email +- emailnotifications +- firebase +- heapdump +- heapdump2 +- help +- info +- le +- lecheck +- leevents +- maintenance +- migrationagents +- mps +- mpsstats +- msg +- nodeconfig +- print +- relays +- removeinactivedevices +- resetserver +- serverupdate +- setmaxtasks +- showpaths +- sms +- swarmstats +- tasklimiter +- trafficdelta +- trafficstats +- updatecheck +- usersessions +- versions +- watchdog +- webpush +- webstats diff --git a/docs/docs/meshcentral/faq.md b/docs/docs/meshcentral/faq.md index 421b9977..1c5b2404 100644 --- a/docs/docs/meshcentral/faq.md +++ b/docs/docs/meshcentral/faq.md @@ -36,7 +36,7 @@ No, you haven't. 6. Here are some examples of what that looks like. -# Can't login on server after first setup +## Can't login on server after first setup You're sure you're typing in everything right, giving it 2FA code and can't login @@ -44,7 +44,40 @@ You're sure you're typing in everything right, giving it 2FA code and can't logi ![](images/2022-08-04-18-19-19.png) -# Branding and Customisation +## Branding and Customization -You can brand and customise MeshCentral almost as much as you like without delving into the code, a few changes in the config.json file and uplaoding images can change the way your system looks. Read more [here](https://ylianst.github.io/MeshCentral/meshcentral/#branding-terms-of-use) +You can brand and customize MeshCentral almost as much as you like without delving into the code, a few changes in the config.json file and uploading images can change the way your system looks. Read more [here](https://ylianst.github.io/MeshCentral/meshcentral/#branding-terms-of-use) + +!!!note + You will need to reinstall the agent for agent customizations to take effect. + +## Mac Clients + +You have to manually grant Mac permissions outside of the agent install process due to the MacOS security system under Security & Privacy > Privacy + +To see the screen (otherwise you just see the menu bar, and otherwise blank) + +![](images/2023-11-29-12-57-15.png) + +To be able to transfer files + +![](images/2023-11-29-12-58-05.png) + +To be able to control keyboard and mouse + +![](images/2023-11-29-12-58-36.png) + +## I'm using CloudFlare and I'm getting a black screen but the mouse moves? + +If you are using CloudFlare for your DNS hosting and your remote screen is black, DONT PANIC! + +Unfortunately, MeshCentral doesn't always work with CloudFlare's Proxy DNS Mode. + +The fix is to simply set the 'Proxy Status' to OFF inside your DNS A Record, within the CloudFlare control panel. + +Simply follow the steps [here](https://developers.cloudflare.com/fundamentals/setup/manage-domains/pause-cloudflare/#disable-proxy-on-dns-records) + +Once done, open your firewall for the `port` and `agentPort` ports of where your meshcentral is hosted, then restart your MeshCentral Server + +There is currently a PINNED GitHub issue about this [here](https://github.com/Ylianst/MeshCentral/issues/5302) diff --git a/docs/docs/meshcentral/images/2023-02-24vscodejsonediting.png b/docs/docs/meshcentral/images/2023-02-24vscodejsonediting.png new file mode 100644 index 00000000..114e575b Binary files /dev/null and b/docs/docs/meshcentral/images/2023-02-24vscodejsonediting.png differ diff --git a/docs/docs/meshcentral/images/2023-11-29-12-57-15.png b/docs/docs/meshcentral/images/2023-11-29-12-57-15.png new file mode 100644 index 00000000..67718be7 Binary files /dev/null and b/docs/docs/meshcentral/images/2023-11-29-12-57-15.png differ diff --git a/docs/docs/meshcentral/images/2023-11-29-12-58-05.png b/docs/docs/meshcentral/images/2023-11-29-12-58-05.png new file mode 100644 index 00000000..f86536c8 Binary files /dev/null and b/docs/docs/meshcentral/images/2023-11-29-12-58-05.png differ diff --git a/docs/docs/meshcentral/images/2023-11-29-12-58-36.png b/docs/docs/meshcentral/images/2023-11-29-12-58-36.png new file mode 100644 index 00000000..deb41c14 Binary files /dev/null and b/docs/docs/meshcentral/images/2023-11-29-12-58-36.png differ diff --git a/docs/docs/meshcentral/images/2023-11-29_140845 - mesh json1.png b/docs/docs/meshcentral/images/2023-11-29_140845 - mesh json1.png new file mode 100644 index 00000000..b000fe1b Binary files /dev/null and b/docs/docs/meshcentral/images/2023-11-29_140845 - mesh json1.png differ diff --git a/docs/docs/meshcentral/images/2023-11-29_140845 - mesh json2.png b/docs/docs/meshcentral/images/2023-11-29_140845 - mesh json2.png new file mode 100644 index 00000000..d530454b Binary files /dev/null and b/docs/docs/meshcentral/images/2023-11-29_140845 - mesh json2.png differ diff --git a/docs/docs/meshcentral/images/7daypowerstate.png b/docs/docs/meshcentral/images/7daypowerstate.png index de545544..c732043e 100644 Binary files a/docs/docs/meshcentral/images/7daypowerstate.png and b/docs/docs/meshcentral/images/7daypowerstate.png differ diff --git a/docs/docs/meshcentral/images/In-production.png b/docs/docs/meshcentral/images/In-production.png new file mode 100644 index 00000000..c1fc2e64 Binary files /dev/null and b/docs/docs/meshcentral/images/In-production.png differ diff --git a/docs/docs/meshcentral/images/OAuth-Internal-External.png b/docs/docs/meshcentral/images/OAuth-Internal-External.png new file mode 100644 index 00000000..13b14c8a Binary files /dev/null and b/docs/docs/meshcentral/images/OAuth-Internal-External.png differ diff --git a/docs/docs/meshcentral/images/agentico.png b/docs/docs/meshcentral/images/agentico.png new file mode 100644 index 00000000..dccb2ab1 Binary files /dev/null and b/docs/docs/meshcentral/images/agentico.png differ diff --git a/docs/docs/meshcentral/images/custom-web-icons.png b/docs/docs/meshcentral/images/custom-web-icons.png new file mode 100644 index 00000000..9edb5569 Binary files /dev/null and b/docs/docs/meshcentral/images/custom-web-icons.png differ diff --git a/docs/docs/meshcentral/images/email-invitation.png b/docs/docs/meshcentral/images/email-invitation.png new file mode 100644 index 00000000..db9d2196 Binary files /dev/null and b/docs/docs/meshcentral/images/email-invitation.png differ diff --git a/docs/docs/meshcentral/images/gc-newproject.png b/docs/docs/meshcentral/images/gc-newproject.png new file mode 100644 index 00000000..715b68f9 Binary files /dev/null and b/docs/docs/meshcentral/images/gc-newproject.png differ diff --git a/docs/docs/meshcentral/images/gc-oauthconsent.png b/docs/docs/meshcentral/images/gc-oauthconsent.png new file mode 100644 index 00000000..a493c589 Binary files /dev/null and b/docs/docs/meshcentral/images/gc-oauthconsent.png differ diff --git a/docs/docs/meshcentral/images/gc-oauthconsent2.png b/docs/docs/meshcentral/images/gc-oauthconsent2.png new file mode 100644 index 00000000..10697dd1 Binary files /dev/null and b/docs/docs/meshcentral/images/gc-oauthconsent2.png differ diff --git a/docs/docs/meshcentral/images/gc-oauthcredentials.png b/docs/docs/meshcentral/images/gc-oauthcredentials.png new file mode 100644 index 00000000..243928b0 Binary files /dev/null and b/docs/docs/meshcentral/images/gc-oauthcredentials.png differ diff --git a/docs/docs/meshcentral/images/gc-oauthscopes.png b/docs/docs/meshcentral/images/gc-oauthscopes.png new file mode 100644 index 00000000..10697dd1 Binary files /dev/null and b/docs/docs/meshcentral/images/gc-oauthscopes.png differ diff --git a/docs/docs/meshcentral/images/gc-playground.webp b/docs/docs/meshcentral/images/gc-playground.webp new file mode 100644 index 00000000..a0fb99f6 Binary files /dev/null and b/docs/docs/meshcentral/images/gc-playground.webp differ diff --git a/docs/docs/meshcentral/index.md b/docs/docs/meshcentral/index.md index 3ebd240f..b25ac0f7 100644 --- a/docs/docs/meshcentral/index.md +++ b/docs/docs/meshcentral/index.md @@ -1,8 +1,8 @@ -# Meshcentral2 Guide +# MeshCentral Guide -[MeshCentral2 Guide](https://meshcentral.com/info/docs/MeshCentral2UserGuide.pdf) +[MeshCentral Guide](https://meshcentral.com/docs/MeshCentral2UserGuide.pdf) -MeshCmd Guide [as .pdf](https://meshcentral.com/info/docs/MeshCmdUserGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral User's Guide v0.2.9.odt?raw=true) +MeshCmd Guide [as .pdf](https://meshcentral.com/docs/MeshCmdUserGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral User's Guide v0.2.9.odt?raw=true) ## Video Walkthru @@ -213,7 +213,7 @@ As indicated before, the settings section of the config.json is equivalent to pa | RedirPort | This is the port for redirecting traffic in the web server. When the server is configured with HTTPS, users that uses HTTP will be redirected to HTTPS. Port 80 is the default port. So, redirection will happen from port 80 to port 443. | | MpsPort | Port for Intel" AMT Management Presence Server to receive Intel" AMT CIRA (Client Initiated Remote Access) connections. The default is port 4433. This port is disabled in LAN mode. If user don"t plan on using Intel" AMT for management, this port can be left as-is. | | TLSOffload | By default this option is set to "false". If set to "true", server will run both web port and the Intel AMT MPS port without TLS with the assumption that a TLS offloading is taking care of this task. For further details, see the "TLS Offloading" section. This option can also be set to the IP address of the reverse-proxy in order to indicate to MeshCental to only trust HTTP X-Forwarded headers coming from this IP address. See the "Reverse-Proxy Setup" section for an example. | -| SelfUpdate | When set to "true" the server will check for a new version and attempt to self-update automatically a bit after midnight local time every day. For this to work, the server needs to run with sufficient permissions to overwrite its own files. If you run the server with more secure, restricted privileges, this option should not be used. If set to a specific version such as "0.2.7-g" when the server will immediately update to the specified version on startup if it"s not already at this version. | +| SelfUpdate | When set to "true" the server will check for a new version and attempt to self-update automatically a bit after midnight local time every day. If set to a specific version such as "1.1.21" the server will immediately update to the specified version on startup if it's not already at this version. | | SessionKey | This is the encryption key used to secure the user"s login session. It will encrypt the browser cookie. By default, this value is randomly generated each time the server starts. If many servers are used with a load balancer, all servers should use the same session key. In addition, one can set this key so that when the server restarts, users do not need to re-login to the server. | | Minify | Default value is 0, when set to 1 the server will serve "minified" web pages, that is, web pages that have all comments, white spaces and other unused characters removed. This reduces the data size of the web pages by about half and reduced the number requests made by the browser. The source code of the web page will not be easily readable, adding "&nominify=1" at the end of the URL will override this option. | | User | Specify a username that browsers will be automatically logged in as. Useful to skip the login page and password prompts. Used heavily during development of MeshCentral. | @@ -305,6 +305,120 @@ When the MongoDB is setup for the first time, a unique identifier is generated a Once peered, all of the servers should act like one single host, no matter which server the user(s) are connected to. +## Email Setup + +We highly recommend the use of an email server (SMTP) because we could allow MeshCentral to verify user account’s email address by sending a confirmation request to the user to complete the account registration and for password recovery, should a user forget account password as illustrated below + +A verification email is sent when a new account is created or if the user requests it in the “My Account” tab. + +![](images/2022-05-19-00-00-05.png) + +The password recovery flow when “Reset Account” is triggered at the login page. + +![](images/2022-05-19-00-00-18.png) + +Both account verification and password recovery are triggered automatically once SMTP mail server configuration is included into the config.json file. + +#### SMTP: User/Pass +##### Normal Server + +Update the config.json with “smtp” section as shown below and restart the server. + +```json +{ + "smtp": { + "host": "smtp.server.com", + "port": 25, + "from": "myaddress@server.com", + "user": "myaddress@server.com", # Optional + "pass": "mypassword", # Optional + "tls": false # Optional, default false + } +} +``` + +Please map the host, port values to connect to the right host that provides this SMTP service. For “from” value, administrators may put something like donotreply@server.com, but often times it needs to be a valid address since SMTP server will not send out messages with an invalid reply address. + +Some SMTP servers will require a valid username and password to login to the mail server. This is to prevent unauthorized e-mail correspondence. TLS option can be set to ‘true’ if the SMTP server requires TLS. + +##### Gmail + +One option is to configure MeshCentral work with Google Gmail by setting “host” with smtp.gmail.com, and “port” with 587. In the config.json file, use user’s Gmail address for both “from” and “user” and Gmail password in the “pass” value. You will also need to enable “Less secure app access” in for this Google account. It’s in the account settings, security section: + +![](images/2022-05-19-00-01-19.png) + +If a Google account is setup with 2-factor authentication, the option to allow less secure applications not be available. Because the Google account password is in the MeshCentral config.json file and that strong authentication can’t be used, it’s preferable to use a dedicated Google account for MeshCentral email. + +#### SMTP: OAuth Authentication +##### Gmail + +Google has announced that less secure app access will be phased out. For Google Workspace or G-Suite accounts, the following process can be used to allow OAuth2 based authentication with Google's SMTP server. It is likely a very similar process for regular Gmail accounts. + +Start by visiting the Google API console: + +https://console.developers.google.com/ + +First, you will create a new project. Name it something unique in case you need to create more in the future. In this example, I've named the project "MeshCentral" + +![](images/gc-newproject.png) + +Click on the "OAuth Consent Screen" link, Under "APIs and Services" from the left hand menu: + +![](images/gc-oauthconsent.png) + +If you have a Google Workspace account, you will have the option to choose "Internal" application and skip the next steps. If not, you will be required to provide Google with information about why you want access, as well as verifying domain ownership. + +![](images/OAuth-Internal-External.png) + +Add the Gmail address under which you have created this project to the fields labelled ‘User support email’ and ‘Developer contact information’ so that you will be allowed for authentication. After that, you will want to add a scope for your app, so that your token is valid for gmail: + +![](images/gc-oauthscopes.png) + +Once this is complete, the next step will be to add credentials. + +![](images/gc-oauthcredentials.png) + +Choose OAuth Client + +You will obtain a Client ID and a Client secret once you've completed the process. Be sure to store the secret immediately, as you won't be able to retreive it after you've dismissed the window. + +Next, you will need to visit the Google OAuth Playground: + +https://developers.google.com/oauthplayground + +![](images/gc-playground.webp) + +Enter your Client ID and secret from the last step. On the left side of the page, you should now see a text box that allows you to add your own scopes. Enter https://mail.google.com and click Authorize API. + +You will need to follow the instructions provided to finish the authorization process. Once that is complete, you should receive a refresh token. The refresh token, Client ID and Client Secret are the final items we need to complete the SMTP section of our config.json. It should now look something like this: + +``` +"smtp": { + "host": "smtp.gmail.com", + "port": 587, + "from": "my@googleaccount.com", + "auth": { + "clientId": "", + "clientSecret": "", + "refreshToken": "" + }, + "user": "noreply@authorizedgooglealias.com", + "emailDelaySeconds": 10, + "tls": false, + "verifyEmail": true + } +``` + + +Regardless of what SMTP account is used, MeshCentral will perform a test connection to make sure the server if working as expected when starting. Hence, the user will be notified if Meshcentral and SMTP server has been configured correctly as shown below. + +![](images/2022-05-19-00-01-43.png) + +After successfully configuring the Gmail SMTP server, switch the OAuth 'Publishing Status' from `Testing` to `In Production`. This step prevents the need for frequent refresh token generation. Verification of your project isn't required to make this change. + +![](images/In-production.png) + + ## Database A critical component of MeshCentral is the database. The database stores all of the user account information, groups and node data, historical power and event, etc. By default MeshCentral uses NeDB (https://github.com/louischatriot/nedb) that is written entirely in NodeJS and is setup automatically when MeshCentral is installed with the npm tool. The file “meshcentral.db” will be created in the “meshcentral-data” folder when MeshCentral is first launched. This database works well for small deployments scenarios. @@ -438,14 +552,14 @@ To make this happen, we will be using the following command line options from Me | --dblistconfigfiles | List the names and size of all configuration files in the database. | | --dbshowconfigfile (filename) | Show the content of a specified filename from the database. --configkey is required. | | --dbdeleteconfigfiles | Delete all configuration files from the database. | -| --dbpushconfigfiles (*) or (folder path) | Push a set of configuration files into the database, removing any existing files in the process. When * is specified, the “meshcentral-data” folder up pushed into the database. --configkey is required. | +| --dbpushconfigfiles '*' or (folder path) | Push a set of configuration files into the database, removing any existing files in the process. When * is specified, the “meshcentral-data” folder up pushed into the database. --configkey is required. | | --dbpullconfigfiles (folder path) | Get all of the configuration files from the database and place them in the specified folder. Files in the target folder may be overwritten. --configkey is required. | | --loadconfigfromdb (key) | Runs MeshCentral server using the configuration files found in the database. The configkey may be specified with this command or --configkey can be used. | Once we have MeshCentral running as expected using the “meshcentral-data” folder, we can simply push that configuration into the database and run using the database alone like this: ``` -node ./node_modules/meshcentral --dbpushconfigfiles * --configkey mypassword +node ./node_modules/meshcentral --dbpushconfigfiles '*' --configkey mypassword node ./node_modules/meshcentral --loadconfigfromdb mypassword --mongodb "mongodb://127.0.0.1:27017/meshcentral" ``` @@ -609,46 +723,6 @@ All the lines that start with a number or `:` will be used, everything else is i 95.85.81.0/24 ``` -## Email Setup - -We highly recommend the use of an email server (SMTP) because we could allow MeshCentral to verify user account’s email address by sending a confirmation request to the user to complete the account registration and for password recovery, should a user forget account password as illustrated below - -A verification email is sent when a new account is created or if the user requests it in the “My Account” tab. - -![](images/2022-05-19-00-00-05.png) - -The password recovery flow when “Reset Account” is triggered at the login page. - -![](images/2022-05-19-00-00-18.png) - -Both account verification and password recovery are triggered automatically once SMTP mail server configuration is included into the config.json file. Update the config.json with “smtp” section as shown below and restart the server. - -```json -{ - "smtp": { - "host": "smtp.server.com", - "port": 25, - "from": "myaddress@server.com", - "user": "myaddress@server.com",  Optional - "pass": "mypassword",  Optional - "tls": false  Optional, default false - } -} -``` - -Please map the host, port values to connect to the right host that provides this SMTP service. For “from” value, administrators may put something like donotreply@server.com, but often times it needs to be a valid address since SMTP server will not send out messages with an invalid reply address. - -Some SMTP servers will require a valid username and password to login to the mail server. This is to prevent unauthorized e-mail correspondence. TLS option can be set to ‘true’ if the SMTP server requires TLS. - -One option is to configure MeshCentral work with Google Gmail* by setting “host” with smtp.gmail.com, and “port” with 587. In the config.json file, use user’s Gmail* address for both “from” and “user” and Gmail* password in the “pass” value. You will also need to enable “Less secure app access” in for this Google account. It’s in the account settings, security section: - -![](images/2022-05-19-00-01-19.png) - -If a Google account is setup with 2-factor authentication, the option to allow less secure applications not be available. Because the Google account password is in the MeshCentral config.json file and that strong authentication can’t be used, it’s preferable to use a dedicated Google account for MeshCentral email. - -Regardless of what SMTP account is used, MeshCentral will perform a test connection to make sure the server if working as expected when starting. Hence, the user will be notified if Meshcentral and SMTP server has been configured correctly as shown below. - -![](images/2022-05-19-00-01-43.png) ## Embedding MeshCentral @@ -827,6 +901,12 @@ In this example, we will: - MeshCentral will read the NGINX web certificate so agents will perform correct server authentication. - NGINX will be setup with long timeouts, because agents have long standard web socket connections. +!!!note + With SELinux, NGINX reverse proxy requires 'setsebool -P httpd_can_network_relay 1' + Caution: httpd_can_network_relay only allows certain ports + Confirm you are using ports from this subset in MeshCentral + If you want to use a different port then you will need to add it to http_port_t + Let’s get started by configuring MeshCentral with the following values in config.json: ```json @@ -1014,8 +1094,7 @@ First we will start with the MeshCentral configuration, here is a minimal config }, "domains": { "": { - "certUrl": "https://127.0.0.1:443/", - "agentConfig": [ "webSocketMaskOverride=1" ], + "certUrl": "https://127.0.0.1:443/" } } } @@ -1199,77 +1278,7 @@ And taking authentication to the next step is removing the login page entirely.
-## Branding & Terms of use - -Whitelabeling your MeshCentral installation to personalize it to your companies brand, as well as having your own terms of use is one of the first things many people do after installation. - -
- -
- -### Branding - -You can put you own logo on the top of the web page. To get started, get the file “logoback.png” from the folder “node_modules/meshcentral/public/images” and copy it to your “meshcentral-data” folder. In this example, we will change the name of the file “logoback.png” to “title-mycompany.png”. Then use any image editor to change the image and place your logo. - -![](images/2022-05-19-00-38-51.png) - -Once done, edit the config.json file and set one or all of the following values: - -```json -"domains": { - "": { - "Title": "", - "Title2": "", - "TitlePicture": "title-sample.png", - "loginPicture": "logintitle-sample.png", - "welcomeText": "This is sample text", - "welcomePicture": "mainwelcome-04.jpg", - "welcomePictureFullScreen": true, - "siteStyle": "1", - "nightMode": "1", - "meshMessengerTitle": "Mesh Chat", - "meshMessengerPicture": "chatimage.png", - "footer": "This is a HTML string displayed at the bottom of the web page when a user is logged in.", - "loginfooter": "This is a HTML string displayed at the bottom of the web page when a user is not logged in." - }, -``` - -This will set the title and sub-title text to empty and set the background image to the new title picture file. You can now restart the serve and take a look at the web page. Both the desktop and mobile sites will change. - -![](images/2022-05-19-00-39-35.png) - -![](images/2022-05-19-00-39-42.png) - -The title image must a PNG image of size 450 x 66. - -You can also customize the server icon in the “My Server” tab. By default, it’s a picture of a desktop with a padlock. - -![](images/2022-05-19-00-40-00.png) - -If, for example, MeshCentral is running on a Raspberry Pi. You may want to put a different picture at this location. Just put a “server.jpg” file that is 200 x 200 pixels in the “meshcentral-data” folder. The time MeshCentral page is loaded, you will see the new image. - -![](images/2022-05-19-00-40-13.png) - -This is great to personalize the look of the server within the web site. - -### Agent Branding - -You can also customize the Agent to add your own logo. - -![](images/2022-08-24-06-42-40.png) - -### Terms of use - -You can change the terms of use of the web site by adding a “terms.txt” file in the “meshcentral-data” folder. The file can include HTML markup. Once set, the server does not need to be restarted, the updated terms.txt file will get used the next time it’s requested. - -For example, placing this in “terms.txt” - -``` -
-This is a test file. -``` - -Will show this on the terms of use web page. +You can also setup [Duo 2FA](https://github.com/Ylianst/MeshCentral/blob/master/docs/docs/meshcentral/security.md#duo-2fa-setup) which is a commertial offering. ## Server Backup & Restore @@ -1724,6 +1733,41 @@ The callback URL will be of the form “https://(servername)/auth-saml-callback Enabling SAML will require MeshCentral to install extra modules from NPM, so depending on your server configuration, you may need to run MeshCentral once manually. +!!!note + MeshCentral only supports "POST". [For example Authentik's](https://github.com/Ylianst/MeshCentral/issues/4725) default setting is to use "Redirect" as a "Service Provider Binding". + +### Generic OpenID Connect Setup + +Generally, if you are using an IdP that supports OpenID Connect (OIDC), you can use a very basic configuration to get started, and if needed, add more specific or advanced configurations later. Here is what your config file will look like with a basic, generic, configuration. + +``` json +{ + "settings": { + "cert": "mesh.your.domain", + "port": 443, + "sqlite3": true + }, + "domains": { + "": { + "title": "Mesh", + "title2": ".Your.Domain", + "authStrategies": { + "oidc": { + "issuer": "https://sso.your.domain", + "clientid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", + "clientsecret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "newAccounts": true + } + } + } + } +} +``` + +As you can see, this is roughly the same as all the other OAuth2 based authentication strategies. These are the basics you need to get started using OpenID Connect because it's still authenticating with OAuth2. If you plan to take advantage of some of the more advanced features provided by this strategy you should consider reading the [additional strategy documentation](./openidConnectStrategy.md). + +> NOTE: MeshCentral will use `https://mesh.your.domain/auth-oidc-callback` as the default redirect uri. + ## Improvements to MeshCentral In 2007, the first version of MeshCentral was built. We will refer to it as “MeshCentral1”. When MeshCentral1 was designed, HTML5 did not exist and web sockets where not implemented in any of the major browsers. Many design decisions were made at the time that are no longer optimal today. With the advent of the latest MeshCentral, MeshCentral1 is no longer supported and MeshCentral v2 has been significantly redesigned and mostly re-written based of previous version. Here is a list of improvements made in MeshCentral when compared with MeshCentral1: @@ -1861,4 +1905,4 @@ MeshCentral has built-in web-based integration of SSH in the "Terminal" tab and
-
\ No newline at end of file + diff --git a/docs/docs/meshcentral/openidConnectStrategy.md b/docs/docs/meshcentral/openidConnectStrategy.md new file mode 100644 index 00000000..4b6e4911 --- /dev/null +++ b/docs/docs/meshcentral/openidConnectStrategy.md @@ -0,0 +1,671 @@ +# Using the OpenID Connect Strategy on MeshCentral + +## Overview + +### Introduction + +There is a lot of information to go over, but first, why OpenID Connect? + +Esentially its because its both based on a industry standard authorization protocol, and is becoming an industry standard authentication protocol. Put simply it's reliable and reusable, and we use OpenID Connect for exactly those reasons, almost every everyone does, and we want to be able to integrate with almost anyone. This strategy allows us to expand the potential of MeshCentral through the potential of OpenID Connect. + +In this document, we will learn about the OpenID Connect specification at a high level, and then use that information to configure the OpenID Connect strategy for MeshCentral using a generic OpenID Connect compatible IdP. After that we will go over some advanced configurations and then continue by explaining how to use the new presets for popular IdPs, specifically Google or Azure. Then we will explore the configuration and usage of the groups feature. + +> ATTENTION: As of MeshCentral `v1.1.22` there are multiple config options being depreciated. Using any of the old configs will only generate a warning in the authlog and will not stop you from using this strategy at this time. If there is information found in both the new and old config locations the new config location will be used. We will go over the specifics later, now lets jump in. + +### Chart of Frequently Used Terms and Acronyms +| Term | AKA | Descriptions | +| --- | --- | --- | +| OAuth 2.0 | OAuth2 | OAuth 2.0 is the industry-standard protocol for user *authorization*. | +| OpenID Connect | OIDC | Identity layer built on top of OAuth2 for user *authentication*. | +| Identity Provider | IdP | The *service used* to provide authentication and authorization. | +| Preset Configs | Presets | Set of *pre-configured values* to allow some specific IdPs to connect correctly. | +| OAuth2 Scope | Scope | A flag *requesting access* to a specific resource or endpoint | +| OIDC Claim | Claim | A *returned property* in the user info provided by your IdP | +| User Authentication | AuthN | Checks if you *are who you say you are*. Example: Username and password authentication | +| User Authorization | AuthZ | Check if you have the *permissions* required to access a specific resource or endpoint | + +### OpenID Connect Technology Overview + +OpenID Connect is a simple identity layer built on top of the OAuth2 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an “Authorization Server”, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner. + +OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and logout, when it makes sense for them. + +That description was straight from [OpenID Connect Documentation](https://openid.net/connect/), but basically, OAuth2 is the foundation upon which OpenID Connect was built, allowing for wide ranging compatability and interconnection. OpenID Connect appends the secure user *authentication* OAuth2 is known for, with user *authorization* by allowing the request of additional *scopes* that provide additional *claims* or access to API's in an easily expandable way. + +### Annotations + +#### Own IDP, CA and Docker + +If you operate your own identity provider, your own certification authority and MeshCentral via Docker, it is necessary to provide the complete certificate chain, otherwise NodeJS (in particular the openid-client module) will refuse the connection to the IDP server. + +The following errors can be found in the log file: +> OIDC: Discovery failed. + +> UNABLE_TO_GET_ISSUER_CERT_LOCALLY + +To solve this problem, the certificate chain in PEM format must be placed in the data directory and the following entry must be added to the docker-compose.yml file in the “environment” section: +``` + environment: + - NODE_EXTRA_CA_CERTS=/opt/meshcentral/meshcentral-data/chain.pem +``` + +## Basic Config + +### *Introduction* + +Generally, if you are using an IdP that supports OIDC, you can use a very basic configuration to get started, and if needed, add more specific or advanced configurations later. Here is what your config file will look like with a basic, generic, configuration. + +### *Basic Config File Example* + +``` json +{ + "settings": { + "cert": "mesh.your.domain", + "port": 443, + "sqlite3": true + }, + "domains": { + "": { + "title": "MeshCentral", + "title2": "Your sub-title", + "authStrategies": { + "oidc": { + "issuer": "https://sso.your.domain", + "clientid": "2d5685c5-0f32-4c1f-9f09-c60e0dbc948a", + "clientsecret": "7PiGSLSLL4e7NGi67KM229tfK7Z7TqzQ", + "newAccounts": true + } + } + } + } +} +``` + +As you can see, this is roughly the same as all the other OAuth2 based authentication strategies. These are the basics you need to get started, however, if you plan to take advantage of some of the more advanced features provided by this strategy, you'll need to keep reading. + +In this most basic of setups, you only need the URL of the issuer, as well as a client ID and a client secret. Notice in this example that the callback URL (or client redirect uri) is not configured, thats because MeshCentral will use `https://mesh.your.domain/auth-oidc-callback` as the default. Once you've got your configuration saved, restart MeshCentral and you should see an OpenID Connect Single Sign-on button on the login screen. + +> WARNING: The redirect endpoint must EXACTLY match the value provided to your IdP or your will deny the connection. + +> ATTENTION: You are required to configure the cert property in the settings section for the default domain, and configure the dns property under each additional domain. + +## Advanced Options + +### Overview + +There are plenty of options at your disposal if you need them. In fact, you can configure any property that node-openid-client supports. The openid-client module supports far more customization than I know what to do with, if you want to know more check out [node-openid-client on GitHub](https://github.com/panva/node-openid-client) for expert level configuration details. There are plenty of things you can configure with this strategy and there is a lot of decumentation behind the tools used to make this all happen. I strongly recommend you explore the [config schema](https://github.com/Ylianst/MeshCentral/blob/master/meshcentral-config-schema.json), and if you have a complicated config maybe check out the [openid-client readme](https://github.com/panva/node-openid-client/blob/main/docs/README.md). Theres a list of resources at the end if you want more information on any specific topics. In the meantime, let’s take a look at an example of what your config file could look with a slightly more complicated configuration, including multiple manually defined endpoints. + +#### *Advanced Config File Example* + +``` json +{ + "settings": { + "cert": "mesh.your.domain", + "port": 443, + "redirPort": 80, + "AgentPong": 300, + "TLSOffload": "192.168.1.50", + "SelfUpdate": false, + "AllowFraming": false, + "sqlite3": true, + "WebRTC": true + }, + "domains": { + "": { + "title": "Mesh", + "title2": ".Your.Domain", + "orphanAgentUser": "~oidc:e48f8ef3-a9cb-4c84-b6d1-fb7d294e963c", + "authStrategies": { + "oidc": { + "issuer": { + "issuer": "https://sso.your.domain", + "authorization_endpoint": "https://auth.your.domain/auth-endpoint", + "token_endpoint": "https://tokens.sso.your.domain/token-endpoint", + "end_session_endpoint": "https://sso.your.domain/logout", + "jwks_uri": "https://sso.your.domain/jwks-uri" + }, + "client": { + "client_id": "110d5612-0822-4449-a057-8a0dbe26eca5", + "client_secret": "4TqST46K53o3Z2Q88p39YwR6YwJb7Cka", + "redirect_uri": "https://mesh.your.domain/auth-oidc-callback", + "post_logout_redirect_uri": "https://mesh.your.domain/login", + "token_endpoint_auth_method": "client_secret_post", + "response_types": "authorization_code" + }, + "custom": { + "scope": [ "openid", "profile", "read.EmailAlias", "read.UserProfile" ], + "preset": null + }, + "groups": { + "recursive": true, + "required": ["Group1", "Group2"], + "siteadmin": ["GroupA", "GroupB"], + "revokeAdmin": true, + "sync": { + "filter": ["Group1", "GroupB", "OtherGroup"] + }, + "claim": "GroupClaim", + "scope": "read.GroupMemberships" + }, + "logouturl": "https://sso.your.domain/logout?r=https://mesh.your.domain/login", + "newAccounts": true + }, + {...} + } + } + } +} +``` + +### "Issuer" Options + +#### *Introduction* + +In the advanced example config above, did you notice that the issuer property has changed from a *string* to an *object* compared to the basic example? This not only allows for much a much smaller config footprint when advanced issuer options are not required, it successfully fools you in to a false sense of confidence early on in this document. If you are manually configuring the issuer endpoints, keep in mind that MeshCentral will still attempt to discover **ALL** issuer information. Obviously if you manually configure an endpoint, it will be used even if the discovered information is different from your config. + +> NOTE: If you are using a preset, you dont need to define an issuer. If you do, the predefined information will be ignored. + +#### *Common Config Chart* + +| Name | Description | Default | Example | Required | +| --- | --- | --- | --- | --- | +| `issuer` | The primary URI that represents your Identity Providers authentication endpoints. | N/A | `"issuer": "https://sso.your.domain"`
`"issuer": { "issuer": "https://sso.your.domain" }` | Unless using preset. | + +#### *Advanced Config Example* + +``` json +"issuer": { + "issuer": "https://sso.your.domain", + "authorization_endpoint": "https://auth.your.domain/auth-endpoint", + "token_endpoint": "https://tokens.sso.your.domain/token-endpoint", + "end_session_endpoint": "https://sso.your.domain/logout", + "jwks_uri": "https://sso.your.domain/jwks-uri" +}, +``` + +#### *Required and Commonly Used Configs* + +The `issuer` property in the `issuer` object is the only one required, and its only required if you aren't using a preset. Besides the issuer, these are mostly options related to the endpoints and their configuration. The schema below looks intimidating but it comes down to being able to support any IdP. Setting the issuer, and end_session_endpoint are the two main ones you want to setup. + +#### *Schema* + +``` json +"issuer": { + "type": ["string","object"], + "format": "uri", + "description": "Issuer options. Requires issuer URI (issuer.issuer) to discover missing information unless using preset", + "properties": { + "issuer": { "type": "string", "format": "uri", "description": "URI of the issuer." }, + "authorization_endpoint": { "type": "string", "format": "uri" }, + "token_endpoint": { "type": "string", "format": "uri" }, + "jwks_uri": { "type": "string", "format": "uri" }, + "userinfo_endpoint": { "type": "string", "format": "uri" }, + "revocation_endpoint": { "type": "string", "format": "uri" }, + "introspection_endpoint": { "type": "string", "format": "uri" }, + "end_session_endpoint": { + "type": "string", + "format": "uri", + "description": "URI to direct users to when logging out of MeshCentral.", + "default": "this.issuer/logout" + }, + "registration_endpoint": { "type": "string", "format": "uri" }, + "token_endpoint_auth_methods_supported": { "type": "string" }, + "token_endpoint_auth_signing_alg_values_supported": { "type": "string" }, + "introspection_endpoint_auth_methods_supported": { "type": "string" }, + "introspection_endpoint_auth_signing_alg_values_supported": { "type": "string" }, + "revocation_endpoint_auth_methods_supported": { "type": "string" }, + "revocation_endpoint_auth_signing_alg_values_supported": { "type": "string" }, + "request_object_signing_alg_values_supported": { "type": "string" }, + "mtls_endpoint_aliases": { + "type":"object", + "properties": { + "token_endpoint": { "type": "string", "format": "uri" }, + "userinfo_endpoint": { "type": "string", "format": "uri" }, + "revocation_endpoint": { "type": "string", "format": "uri" }, + "introspection_endpoint": { "type": "string", "format": "uri" } + } + } + }, + "additionalProperties": false +}, +``` + +### "Client" Options + +#### *Introduction* + +There are just about as many option as possible here since openid-client also provides a Client class, because of this you are able to manually configure the client how ever you need. This includes setting your redirect URI to any available path, for example, if I was using the "google" preset and wanted to have Google redirect me back to "https://mesh.your.domain/oauth2/oidc/redirect/givemebackgooglemusicyoujerks", MeshCentral will now fully support you in that. One of the other options is the post logout redirect URI, and it is exactly what it sounds like. After MeshCentral logs out a user using the IdPs end session endpoint, it send the post logout redirect URI to your IdP to forward the user back to MeshCentral or to an valid URI such as a homepage. + +> NOTE: The client object is required, however an exception would be with using old configs, which will be discussed later. + +#### *Common Configs* + +| Name | Description | Default | Example | Required | +| --- | --- | --- | --- | --- | +| `client_id` | The client ID provided by your Identity Provider (IdP) | N/A | `bdd6aa4b-d2a2-4ceb-96d3-b3e23cd17678` | `true` | +| `client_secret` | The client secret provided by your Identity Provider (IdP) | N/A | `vUg82LJ322rp2bvdzuVRh3dPn3oVo29m` | `true` | +| `redirect_uri` | "URI your IdP sends you after successful authorization. | `https://mesh.your.domain/auth-oidc-callback` | `https://mesh.your.domain/oauth2/oidc/redirect` | `false` | +| `post_logout_redirect_uri` | URI for your IdP to send you after logging out of IdP via MeshCentral. | `https://mesh.your.domain/login` | `https://site.your.other.domain/login` | `false` | + +#### *Advanced Config Example* + +``` json +"client": { + "client_id": "00b3875c-8d82-4238-a8ef-25303fa7f9f2", + "client_secret": "7PP453H577xbFDCqG8nYEJg8M3u8GT8F", + "redirect_uri": "https://mesh.your.domain/auth-oidc-callback", + "post_logout_redirect_uri": "https://mesh.your.domain/login", + "token_endpoint_auth_method": "client_secret_post", + "response_types": "authorization_code" +}, +``` + +#### *Required and Commonly Used Configs* + +There are many available options you can configure but most of them go unused. Although there are a few *commonly used* properties. The first two properties, `client_id` and `client_secret` are required. The next one `redirect_uri` is used to setup a custom URI for the redirect back to MeshCentral after being authenicated by your IdP. The `post_logout_redirect_uri` property is used to tell your IdP where to send you after being logged out. These work in conjunction with the issuers `end_session_url` to automatically fill in any blanks in the config. + +#### *Schema* +``` json +"client": { + "type": "object", + "description": "OIDC Client Options", + "properties": { + "client_id": { + "type": "string", + "description": "REQUIRED: The client ID provided by your Identity Provider (IdP)" + }, + "client_secret": { + "type": "string", + "description": "REQUIRED: The client secret provided by your Identity Provider (IdP)" + }, + "redirect_uri": { + "type": "string", + "format": "uri", + "description": "URI your IdP sends you after successful authorization. This must match what is listed with your IdP. (Default is https://[currentHost][currentPath]/auth-oidc-callback)" + }, + "post_logout_redirect_uri": { + "type": "string", + "format": "uri", + "description": "URI for your IdP to send you after logging out of IdP via MeshCentral.", + "default": "https:[currentHost][currentPath]/login" + }, + "id_token_signed_response_alg": { "type": "string", "default": "RS256" }, + "id_token_encrypted_response_alg": { "type": "string" }, + "id_token_encrypted_response_enc": { "type": "string" }, + "userinfo_signed_response_alg": { "type": "string" }, + "userinfo_encrypted_response_alg": { "type": "string" }, + "userinfo_encrypted_response_enc": { "type": "string" }, + "response_types": { "type": ["string", "array"], "default": ["code"] }, + "default_max_age": { "type": "number" }, + "require_auth_time": { "type": "boolean", "default": false }, + "request_object_signing_alg": { "type": "string" }, + "request_object_encryption_alg": { "type": "string" }, + "request_object_encryption_enc": { "type": "string" }, + "token_endpoint_auth_method": { + "type": "string", + "default": "client_secret_basic", + "enum": [ "none", "client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt" ] + }, + "introspection_endpoint_auth_method": { + "type": "string", + "default": "client_secret_basic", + "enum": [ "none", "client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt" ] + }, + "revocation_endpoint_auth_method": { + "type": "string", + "default": "client_secret_basic", + "enum": [ "none", "client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt" ] + }, + "token_endpoint_auth_signing_alg": { "type": "string" }, + "introspection_endpoint_auth_signing_alg": { "type": "string" }, + "revocation_endpoint_auth_signing_alg": { "type": "string" }, + "tls_client_certificate_bound_access_tokens": { "type": "boolean" } + }, + "required": [ "client_id", "client_secret" ], + "additionalProperties": false +}, +``` + +### "Custom" Options + +#### *Introduction* + +These are all the options that dont fit with the issuer or client, including the presets. The presets define more than just the issuer URL used in discovery, they also define API endpoints, and specific ways to assemble your data. You are able to manually override most of the effects of the preset, but not all. You are able to manually configure the *scope* of the authorization request though, as well as choose which claims to use if your IdP uses something other than the defaults. + +> NOTE: The scope must be a string, an array of strings, or a space separated list of scopes as a single string. + +#### *Common Config Chart* + +| Name | Description | Default | Example | Required | +| -------- | ------------------------------------------------ | --------------------------------------------------------- | ----------------------------------- | -------- | +| `scope` | A list of scopes to request from the issuer. | `"openid profile email"` | `["openid", "profile"]` | `false` | +| `claims` | A group of claims to use instead of the defaults | Defauts to name of property except that `uuid` used `sub` | `"claims": {"uuid": "unique_name"}` | `false` | + +#### *Advanced Config Example* + +``` json +"custom": { + "scope": [ "openid", "profile", "read.EmailAlias", "read.UserProfile" ], + "preset": null, + "claims": { + "name": "nameOfUser", + "email": "publicEmail" + } +}, +``` + +> NOTE: You can `preset` to null if you want to explicitly disable presets. + +#### *Required and Commonly Used Configs* + +As should be apparent by the name alone, the custom property does not need to be configured and is used for optional or advanced configurations. With that said, lets look at few common options strategy will default to using the `openid`, `profile`, and `email` scopes to gather the required information about the user, if your IdP doesn't support or require all these, you can set up the scope manually. Combine that with the ability to set the group scope and you can end up with an entirely custom scope being sent to your IdP. Not to mention the claims property, which allows you to pick and choose what claims to use to gather your data in case you have issues with any of the default behaviors of OpenID Connect and your IdP. This is also where you would set the preset and any values required by the presets. + +#### *Schema* +``` json +"custom": { + "type": "object", + "properties": { + "scope": { + "type": ["string", "array"], + "description": "A list of scopes to request from the issuer.", + "default": "openid profile email", + "examples": ["openid", ["openid", "profile"], "openid profile email", "openid profile email groups"] + }, + "claims": { + "type": "object", + "properties": { + "email": { "type": "string" }, + "name": { "type": "string" }, + "uuid": { "type": "string" } + } + }, + "preset": { "type": "string", "enum": ["azure", "google"]}, + "tenant_id": { "type": "string", "description": "REQUIRED FOR AZURE PRESET: Tenantid for Azure"}, + "customer_id": { "type": "string", "description": "REQUIRED FOR GOOGLE PRESET IF USING GROUPS: Customer ID from Google, should start with 'C'."} + }, + "additionalProperties": false +}, +``` + +### "Groups" Options + +#### *Introduction* + +The groups option allows you to use the groups you already have with your IdP in MeshCentral in a few ways. First you can set a group that the authorized user must be in to sign in to MeshCentral. You can also allow users with the right memberships automatic admin privlidges, and there is even an option to revoke privlidges if the user is NOT in the admin group. Besides these filters, you can filter the sync property to mirror only certain groups as MeshCentral User Groups, dynamically created as the user logs in. You can of course simply enable sync and mirror all groups from your IdP as User Groups. Additionally you can define the scope and claim of the groups for a custom setup, again allowing for a wide range of IdPs to be used, even without a preset. + +#### *Common Config Chart* + +| Name | Description | Default | Example | Required | +| --- | --- | --- | --- | --- | +| `sync` | Allows you to mirror user groups from your IdP. | `false` | `"sync": { "filter": ["Group1", "Group2"] }`
`"sync": true` | `false` | +| `required` | Access is only granted to users who are a member
of at least one of the listed required groups. | `undefined` | `"required": ["Group1", "Group2"]` | `false` | +| `siteadmin` | Full site admin priviledges will be granted to users
who are a member of at least one of the listed admin groups | `undefined` | `"siteadmin": ["Group1", "Group2"]` | `false` | +| `revokeAdmin` | If true, admin privileges will be revoked from users
who arent a member of at least one of the listed admin groups. | `true` | `"revokeAdmin": false` | `false` | + +#### *Advanced Config Example* + +``` json +"groups": { + "recursive": true, + "required": ["Group1", "Group2"], + "siteadmin": ["GroupA", "GroupB"], + "revokeAdmin": false, + "sync": { + "filter": ["Group1", "GroupB", "OtherGroup"] + }, + "claim": "GroupClaim", + "scope": "read.GroupMemberships" +}, +``` + +#### *Required and Commonly Used Configs* + +As you can see in the schema below, there aren't any required properties in the groups object, however there are some commonly used ones. The first, and maybe most commonly used one, is the sync property. The sync property mirrors IdP provided groups into MeshCentral as user groups. You can then configure access as required to those groups, and as users log in, they will be added to the now existing groups if they are a member. You also have other options like using a custom *scope* or *claim* to get your IdP communicating with MeshCentral properly, without the use of preset configs. You also can set the required property if you need to limit authorization to users that are a member of at least one of the groups you set. or the siteadmin property to grant admin privilege, with the revokeAdmin property available to allow revoking admin rights also. + +#### *Schema* + +``` json +"groups": { + "type": "object", + "properties": { + "recursive": { + "type": "boolean", + "default": false, + "description": "When true, the group memberships will be scanned recursively." + }, + "required": { + "type": [ "string", "array" ], + "description": "Access is only granted to users who are a member of at least one of the listed required groups." + }, + "siteadmin": { + "type": [ "string", "array" ], + "description": "Full site admin priviledges will be granted to users who are a member of at least one of the listed admin groups." + }, + "revokeAdmin": { + "type": "boolean", + "default": false, + "description": "If true, admin privileges will be revoked from users who are NOT a member of at least one of the listed admin groups." + }, + "sync": { + "type": [ "boolean", "object" ], + "default": false, + "description": "If true, all groups found during user login are mirrored into MeshCentral user groups.", + "properties": { + "filter": { + "type": [ "string", "array" ], + "description": "Only groups listed here are mirrored into MeshCentral user groups." + } + } + }, + "scope": { "type": "string", "default": "groups", "description": "Custom scope to use." }, + "claim": { "type": "string", "default": "groups", "description": "Custom claim to use." } + }, + "additionalProperties": false +} +``` + +## Preset OpenID Connect Configurations + +### Overview + +#### *Introduction* + +Google is a blah and is used by tons of blahs as its so great. Lets move on. + +#### *Common Config Chart* + +> NOTE: All settings directly related to presets are in the custom section of the config. + +| Name | Description | Example | Required | +| --- | --- | --- | --- | +| `preset` | Manually enable the use of a preset. | `"preset": "google"`
`"preset": "azure"` | `false` | +| `customer_id` | Customer ID of the Google Workspaces instace you
plan to use with the groups feature.| `"customer_id": ["Group1", "Group2"]` | If `google` preset is used with `groups` feature | +| `tenant_id` | Tenant ID from Azure AD, this is required to use
the `azure` preset as it is part of the issuer url. | `"siteadmin": ["Group1", "Group2"]` | `false` | + +### Google Preset + +#### *Prerequisites* + +> Check out this [documentation](https://developers.google.com/identity/protocols/oauth2/openid-connect) to get ready before we start. + +#### *Basic Config Example* + +``` json +"oidc": { + "client": { + "client_id": "268438852161-r8xa7qxwf3rr0shp1xnpgmm70bnag21p.apps.googleusercontent.com", + "client_secret": "ETFWBX-gFEaxfPXs1tWmAOkuWDFTgoL3nwh" + } +} +``` + +#### *Specifics* + +If you notice above I forgot to add any preset related configs, however because google tags the client ID we can detect that and automatically use the google preset. The above config is tested, the sentive data has been scrambled of course. That said, you would normally use this preset in more advaced setups, let take a look at an example. + +#### *Advanced Example with Groups* + +``` json +"oidc": { + "client": { + "client_id": "424555768625-k7ub3ovqs0yp7mfo0usvyyx51nfii61c.apps.googleusercontent.com", + "client_secret": "QLBCQY-nRYmjnFWv3nKyHGmwQEGLokP6ldk" + }, + "custom": { + "preset": "google", + "customer_id": "C46kyhmps" + }, + "groups": { + "siteadmin": ["GroupA", "GroupB"], + "revokeAdmin": true, + "sync": true + }, + "callbackURL": "https://mesh.your.domain/auth-oidc-google-callback" +}, +``` + +#### *Customer ID and Groups* + +As always, the client ID and secret are required, the customer ID on the other hand is only required if you plan to take advantage of the groups function *and* the google preset. This also requires you have a customer ID, if you have do, it is available in the Google Workspace Admin Console under Profile->View. Groups work the same as they would with any other IdP but they are pulled from the Workspace groups. + +#### *Schema* + +```json +"custom": { + "type": "object", + "properties": { + "preset": { "type": "string", "enum": ["azure", "google"]}, + "customer_id": { "type": "string", "description": "Customer ID from Google, should start with 'C'."} + }, + "additionalProperties": false +}, +``` + +### Azure Preset + +#### *Prerequisites* + +To configure OIDC-based SSO, you need an Azure account with an active subscription. [Create an account](https://azure.microsoft.com/free/?WT.mc_id=A261C142F) for free. The account used for setup must be of the following roles: Global Administrator, Cloud Application Administrator, Application Administrator, or owner the service principal. + +> Check this [documentation](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/add-application-portal-setup-oidc-sso) for more information. + +#### *Basic Config Example* + +``` json +"oidc": { + "client": { + "client_id": "a1gkl04i-40g8-2h74-6v41-2jm2o2x0x27r", + "client_secret": "AxT6U5K4QtcyS6gF48gndL7Ys22BL15BWJImuq1O" + }, + "custom": { + "preset": "azure", + "tenant_id": "46a6022g-4h33-1451-h1rc-08102ga3b5e4" + } +} +``` + +#### *Specifics* + +As with all other types of configuration for the OIDC strategy, the Azure preset requires a client ID and secret.The tenant ID is used as part of the issuer URI to make even the most basic AuthN requests so it is also required for the azure preset. besides that groups are available to the Azure preset as well as the recursive feature of groups. This allows you to search user groups recursively for groups they have membership in through other groups. + +> NOTE: The Azure AD preset uses the Tenant ID as part of the issuer URI:
`"https://login.microsoftonline.com/"` + `strategy`.custom.tenant_id + `"/v2.0"` + +#### *Advanced Example with Groups* + +``` json +"oidc": { + "client": { + "client_id": "a1gkl04i-40g8-2h74-6v41-2jm2o2x0x27r", + "client_secret": "AxT6U5K4QtcyS6gF48gndL7Ys22BL15BWJImuq1O" + }, + "custom": { + "preset": "azure", + "tenant_id": "46a6022g-4h33-1451-h1rc-08102ga3b5e4" + }, + "groups": { + "recursive": true, + "siteadmin": ["GroupA", "GroupB"], + "revokeAdmin": true, + "sync": true + }, + "callbackURL": "https://mesh.your.domain/auth-oidc-azure-callback" +}, +``` + +#### *Schema* + +```json +"custom": { + "type": "object", + "properties": { + "preset": { "type": "string", "enum": ["azure", "google"]}, + "tenant_id": { "type": "string", "description": "Tenant ID from Azure AD."} + }, + "additionalProperties": false +}, +``` + +## Depreciated Properties + +### Overview + +#### Introduction + +As of MeshCentral `v1.1.22` and the writing of this documentation, the node module that handles everything was changed from [passport-openid-connect](https://github.com/jaredhanson/passport-openidconnect) to [openid-client](https://github.com/panva/node-openid-client). As a result of this change, multiple properties in the config have been depcrecated; this means some options in the strategy arent being used anymore. These are often referred to as "old configs" by this documentation. + +#### *Migrating Old Configs* + +We upgraded but what about all the existing users, we couldn't just invalidate every config pre `v1.1.22`. So in an effort to allow greater flexibility to all users of MeshCentral, and what futures scholars will all agree was an obvious move, all the depreciated configs will continue working as expected. Using any of the old options will just generate a warning in the authlog and will not stop you from using this the OIDC strategy with outdated configs, however if both the equivalent new and old config are set the new config will be used. + +#### *Old Config Example* +```json +"oidc": { + "newAccounts": true, + "clientid": "421326444155-i1tt4bsmk3jm7dri6jldekl86rfpg07r.apps.googleusercontent.com", + "clientsecret": "GNLXOL-kEDjufOCk6pIcTHtaHFOCgbT4hoi" +} +``` + +This example was chosen because I wanted to highlight an advantage of supporting these old configs long term, even in a depreciated status. That is, the ability to copy your existing config from one of the related strategies without making any changes to your config by using the presets. This allows you to test out the oidc strategy without commiting to anything, since the user is always appended with the strategy used to login. In this example, the config was originally a google auth strategy config, changing the `"google"` to `"oidc"` is all that was done to the above config, besides obsfuscation of course. + +#### *Advcanced Old Config Example* + +``` json +"oidc": { + "authorizationURL": "https://sso.your.domain/api/oidc/authorization", + "callbackURL": "https://mesh.your.domain/oauth2/oidc/callback", + "clientid": "tZiPTMDNuSaQPapAQJtwDXVnYjjhQybc", + "clientsecret": "vrQWspJxdVAxEFJdrxvxeQwWkooVcqdU", + "issuer": "https://sso.your.domain", + "tokenURL": "https://sso.your.domain/api/oidc/token", + "userInfoURL": "https://sso.your.domain/api/oidc/userinfo", + "logoutURL": "https://sso.your.domain/logout?rd=https://mesh.your.domain/login", + "groups": { + "recursive": true, + "required": ["Group1", "Group2"], + "siteadmin": ["GroupA", "GroupB"], + "sync": { + "filter": ["Group1", "GroupB", "OtherGroup"] + } + }, + "newAccounts": true +}, +``` + +#### *Upgrading to v1.1.22* + +If you were already using a meticulusly configured oidc strategy, all of your configs will still be used. You will simply see a warning in the logs if any depreciated properties were used. If you check the authLog there are additional details about the old config and provide the new place to put that information. In this advanced config, even the groups will continue to work just as they did before without any user intervention when upgrading from a version of MeshCentral pre v1.1.22. There are no step to take and no action is needed, moving the configs to the new locations is completely optional at the moment. + +# Links + +https://cloud.google.com/identity/docs/reference/rest/v1/groups/list + +https://www.onelogin.com/learn/authentication-vs-authorization + +https://auth0.com/docs/authenticate/protocols/openid-connect-protocol + +https://github.com/panva/node-openid-client + +https://openid.net/connect/ + +> You just read `openidConnectStrategy.ms v1.0.1` by [@mstrhakr](https://github.com/mstrhakr) diff --git a/docs/docs/meshcentral/plugins.md b/docs/docs/meshcentral/plugins.md index 20142a73..4b85b0c5 100644 --- a/docs/docs/meshcentral/plugins.md +++ b/docs/docs/meshcentral/plugins.md @@ -1,16 +1,140 @@ -# Plugins +# Plugins - Installation & Usage !!!note - Plugins are not supported, if you have problems with MeshCentral please disable all plugins before further troubleshooting. + Plugins as such receive **no support** by the main developers of MeshCentral. If you experience problems with MeshCentral please make sure to **disable all plugins before further troubleshooting**! -## Installation +## Use Cases -1. Enable plugins in the configuration and restart MC as described. -2. Log into MC as full administrator. -3. Go my `My Server` -> `Plugins`, hit the Download plugin button. -4. A dialog opens requesting an URL, put in: -5. The plugin pops up in the plugin list below the download button, you can now configure and enable/disable it. +Certain feature requests may not be suitable for all MeshCentral users and thus are available as a plugin. Furthermore users can develop their own plugins - as described further below - to extend functionality or benefit from integrating MeshCentral into their existing application environment. -## List of plugins +## List of publically available plugins + +## Installation of a plugin + +1. First please make sure that you enable plugins in the configuration + >"plugins": { + > "enabled": true + >}, +2. Restart MeshCentral if you needed to change the configuration. +2. Log into MeshCentral as full administrator. +3. Go my `My Server` -> `Plugins`, then hit the Download plugin button. +4. A dialog opens requesting a URL, e.g. put in: +5. The plugin pops up in the plugin list below the download button, you can now configure and enable/disable it. + +# Plugins - Development & Hooks + +!!!note + Plugins as such receive **no support** by the main developers of MeshCentral. If you experience problems with MeshCentral please make sure to **disable all plugins before further troubleshooting**! + +## Overview + +Not all feature requests may be suitable for all MeshCentral users and thus can't be integrated into MeshCentral directly. Hwoever, Instead of maintaining a complete fork of MeshCentral it is much easier to extend MeshCentral's functionality using hooks and writing plugins for it. + +## Anatomy of a plugin: + + - plugin_name/ + -- config.json + -- plugin_name.js + -- modules_meshcore/ // optional + --- plugin_name.js // optional + +## Plugin Configuration File + +A valid JSON object within a file named `config.json` in the root folder of your project. An example: + + { + "name": "Plugin Name", + "shortName": "plugin_name", + "version": "0.0.0", + "author": "Author Name", + "description": "Short Description of the plugin", + "hasAdminPanel": false, + "homepage": "https://www.example.com", + "changelogUrl": "https://raw.githubusercontent.com/User/Project/master/changelog.md", + "configUrl": "https://raw.githubusercontent.com/User/Project/master/config.json", + "downloadUrl": "https://github.com/User/Project/archive/master.zip", + "repository": { + "type": "git", + "url": "https://github.com/User/Project.git" + }, + "versionHistoryUrl": "https://api.github.com/repos/User/Project/tags", + "meshCentralCompat": ">0.4.3" + } + +## Configuration File Properties + +| Field | Required | Type | Description | +| ----------------- | -------- | ----------- | ------------------------------------------------------------ | +| name | Yes | string | a human-readable name for the plugin | +| shortName | Yes | string | an alphanumeric, unique short identifier for the plugin (will be used to access your functions throughout the project | +| version | Yes | string | the current version of the plugin | +| author | No | string | the author's name | +| description | Yes | string | a short, human-readable description of what the plugin does | +| hasAdminPanel | Yes | boolean | `true` or `false`, indicates whether or not the plugin will offer its own administrative interface | +| homepage | Yes | string | the URL of the projects homepage | +| changelogUrl | Yes | string | the URL to the changelog of the project | +| configUrl | Yes | string | the URL to the config.json of the project | +| downloadUrl | Yes | string | the URL to a ZIP of the project (used for installation/upgrades) | +| repository | Yes | JSON object | contains the following attributes | +| repository.type | Yes | string | valid values are `git` and in the future, `npm` will also be supported. | +| repository.url | Yes | string | the URL to the project's repository | +| versionHistoryUrl | No | string | the URL to the project's versions/tags | +| meshCentralCompat | Yes | string | the minimum version string of required compatibility with the MeshCentral server, can be formatted as "0.1.2-c" or ">=0.1.2-c". Currently only supports minimum version, not full semantic checking. | + +## Plugin Hooks + +In essence, hooks are locations in the code which enable developers to tap into a module to either provide alternative behavior or to respond to an event. + +These are separated into the following categories depending on the type of functionality the plugin should offer. + +- Web UI, to modify the MeshCentral admin interface +- Back End, to modify core functionality of the server and communicate with the Web UI layer as well as the Mesh Agent (Node) layer to send commands and data +- Mesh Agent (Node), to introduce functionality to each agent + +### Web UI Hooks + +- `onDeviceRefreshEnd`: called when a device is selected in the MeshCentral web interface +- `registerPluginTab`: callable when a device is selected in the MeshCentral web interface to register a new tab for plugin data, if required. Accepts an object, or function that returns an object, with the following properties: { tabId: "yourShortNameHere", tabTitle: "Your Display Name"}. A tab and div with the associated ID and title will be created for your use +- `onDesktopDisconnect`: called when a remote desktop session is disconnected +- `onWebUIStartupEnd`: called when the page has loaded for the first time after a login / refresh +- `goPageStart`: called before page changes take effect. Passes 2 arguments ( : int, : Event) +- `goPageEnd`: called after page changes take effect. Passes 2 arguments ( : int, : Event) + +#### Exports + +Any function can be exported to the Web UI layer by adding the name of the function to an `exports` array in the plugin object. + +### Back End Hooks + +- `server_startup`: called once when the server starts (or when the plugin is first installed) +- `hook_agentCoreIsStable`: called once when an agent initially checks in +- `hook_processAgentData`: called each time an agent transmits data back to the server +- `hook_userLoggedIn`: called when a user has logged into the web interface +- `hook_setupHttpHandlers`: called before all http handlers are setup + +### Mesh Agent + +Use of the optional file `plugin_name.js` in the optional folder `modules_meshcore` will include the file in the default meshcore file sent to each endpoint. This is useful to add functionality on each of the endpoints. + +## Structure + +Much of MeshCentral revolves around returning objects for your structures, and plugins are no different. Within your plugin you can traverse all the way up to the web server and MeshCentral Server classes to access all the functionality those layers provide. This is done by passing the current object to newly created objects, and assigning that reference to a `parent` variable within that object. + + +## Ping-Pong + +If you build a plugin which makes use of `meshrelay.ashx`, keep in mind to either handle ping-pong messages (`serverPing`, `serverPong`) on the control channel or to request MeshCentral to not send such messages through sending the `noping=1` parameter in the connection URL. For a deeper sight search for "PING/PONG" in `meshrelay.js`. + +## Versioning + +Versioning your plugin correctly and consistently is essential to ensure users of your plugin are prompted to upgrade when it is available. Semantic versioning is recommended. + +## Changelog + +A changelog is highly recommended so that your users know what's changed since their last version. + +## Sample Plugin + +[MeshCentral-Sample](https://github.com/ryanblenis/MeshCentral-Sample) is a simple plugin that, upon disconnecting from remote desktop, prompts the user to enter a manual event (note), pre-filled in with the date and timestamp. diff --git a/docs/docs/meshcentral/security.md b/docs/docs/meshcentral/security.md index 792ba481..ef1dc2d7 100644 --- a/docs/docs/meshcentral/security.md +++ b/docs/docs/meshcentral/security.md @@ -17,3 +17,39 @@ Adjust these items in your `config.json` ``` ![](images/rate_limiting_logins.png) + +## Disabling TLS 1.0/1.1 for AMT + +```json +{ + "settings": { + "mpshighsecurity": true + } +} +``` + +## Duo 2FA setup + +MeshCentral supports Duo as a way for users to add two-factor authentication and Duo offers free accounts for user 10 users. To get started, go to [Duo.com](https://duo.com/) and create a free account. Once logged into Duo, select "Applications" and "Protect an Application" on the left side. Search for "Web SDK" and hit the "Protect" button. You will see a screen with the following information: + + - Client ID + - Client secret + - API hostname + +Copy these three values in a safe place and do not share these values with anyone. Then, in your MeshCentral config.json file, add the following in the domains section: + +```json +{ + "domains": { + "": { + "duo2factor": { + "integrationkey": "ClientId", + "secretkey": "ClientSecret", + "apihostname": "api-xxxxxxxxxxx.duosecurity.com" + } + } + } +} +``` + +Restart MeshCentral and your server should now be Duo capable. Users will see an option to enable it in the "My Account" tab. When enabling it, users will be walked thru the process of downloading the mobile application and going thru a trial run on 2FA. Users that get setup will be added to your Duo account under the "Users" / "Users" screen in Duo. Note that the "admin" user is not valid in Duo, so, if you have a user with the name "Admin" in MeshCentral, they will get an error trying to setup Duo. diff --git a/docs/docs/meshcentral/tipsntricks.md b/docs/docs/meshcentral/tipsntricks.md index 24992415..3126e869 100644 --- a/docs/docs/meshcentral/tipsntricks.md +++ b/docs/docs/meshcentral/tipsntricks.md @@ -7,3 +7,39 @@ The SSH terminal does support color. The issue is going to be the terminal confi ```bash ls -al --color /tmp ``` + +## Fancy config editing with VS Code + +A common problem in the issues is an incorrect config.json. What makes a config incorrect? How can you verify your config is correct? + +Easy! Use Visual Studio Code to edit your config.json and add the schema at the top. + +If you haven't already, download VS code. +Download or copy the config.json to your computer. +Open config.json in code and add the schema as the top line. This schema is the raw JSON file in the MeshCentral repo. + +```json +{ + "$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json", + "settings": { + "your settings go here": "..." + } +} +``` + +Now you have autocomplete, auto-format and validation for your config.json! If you start typing, Code will show the values that are valid for the location you are editing. Words with a red squiggle line are errors. Words with a orange squiggle line are warnings. Hover over both to see the error message and possible fixes. Code can even format your config. + +While this is a huge step up, it's not perfect. If you notice, there are some invalid keys in the screenshot. This is perfectly valid JSON and MeshCentral will ignore them (maybe?). If you paste some configs into the wrong section, code will not tell you it's in the wrong section. Autocomplete will tell you what keys are valid and the type of the value (i.e. string, number, boolean). + +Hopefully this will help verify your config is syntactically correct and prevent needless formatting errors, misspellings, etc. + +![](images/2023-02-24vscodejsonediting.png) + +## Downloading Folders + +If you would like to download folders via Files simply select folder/files then use the zip and download the zip file by clicking on it. + +## Share device groups with AD logins +If you would like to share device groups with different AD users. + +In the config.json set "ldapuserkey" to "sAMAccountName". diff --git a/docs/docs/meshcentral/tokens.md b/docs/docs/meshcentral/tokens.md index c190d674..7086955d 100644 --- a/docs/docs/meshcentral/tokens.md +++ b/docs/docs/meshcentral/tokens.md @@ -8,8 +8,18 @@ ## Software Integration Tokens -Currently, the login tokens in the user manual section 14.1 can't be tracked, deleted or revoked. They are generated with: +!!!warning + You can only have a SINGLE loginTokenKey for your meshcentral server!
+ So if you regenerate a loginTokenKey, the old one will be revoked/deleted! + +You can create/view the Login Token Key with the following: ```bash -node meshcentral --loginTokenKey +node node_modules/meshcentral --loginTokenKey +``` + +You can then reset/revoke/renew the Login Token Key with the following to create a new one: + +```bash +node node_modules/meshcentral --loginTokenKey --loginTokenGen ``` diff --git a/docs/docs/meshcmd/index.md b/docs/docs/meshcmd/index.md index 38528f91..2c4cf1bb 100644 --- a/docs/docs/meshcmd/index.md +++ b/docs/docs/meshcmd/index.md @@ -1,6 +1,6 @@ # MeshCmd -MeshCmd Guide [as .pdf](https://meshcentral.com/info/docs/MeshCmdUserGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCmd User's Guide v0.0.3.odt?raw=true) +MeshCmd Guide [as .pdf](https://meshcentral.com/docs/MeshCmdUserGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCmd User's Guide v0.0.3.odt?raw=true) ## Video Walkthru diff --git a/docs/docs/meshctrl/index.md b/docs/docs/meshctrl/index.md index c8f46b1c..13b74bc9 100644 --- a/docs/docs/meshctrl/index.md +++ b/docs/docs/meshctrl/index.md @@ -1,6 +1,6 @@ # MeshCtrl -MeshCmd Guide [as .pdf](https://meshcentral.com/info/docs/MeshCtrlUsersGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCtrl User's Guide v0.0.1.odt?raw=true) +MeshCmd Guide [as .pdf](https://meshcentral.com/docs/MeshCtrlUsersGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCtrl User's Guide v0.0.1.odt?raw=true) ## Video Walkthru @@ -274,6 +274,7 @@ devicesharing devicepower indexagenterrorlog agentdownload +report ``` You can get this list by just running MeshCtrl without any argument and can get more information on each action by typing “meshctrl help [action]” diff --git a/docs/docs/meshrouter/index.md b/docs/docs/meshrouter/index.md index 057b0515..b99f042e 100644 --- a/docs/docs/meshrouter/index.md +++ b/docs/docs/meshrouter/index.md @@ -2,7 +2,7 @@ ![](images/Aspose.Words.954ea56c-626b-416a-8b2a-efde10ebd3a9.002.png) -MeshCentral Router Guide [as .pdf](https://meshcentral.com/info/docs/MeshCentral2RouterUserGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral%20Router%20User%20Guide%20v0.0.2.odt?raw=true) +MeshCentral Router Guide [as .pdf](https://meshcentral.com/docs/MeshCentral2RouterUserGuide.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral%20Router%20User%20Guide%20v0.0.2.odt?raw=true) ## Video Walkthru @@ -21,7 +21,7 @@ MeshCentral is a remote management web site that connects users to remote comput ## Downloading MeshCentral router is a Windows application that comes built-into the MeshCentral server or can -be downloaded at: +be downloaded at: It’s probably best to use the MeshCentral router that comes with your version of the MeshCentral server as the two will likely be most compatible. A given MeshCentral Router version may not diff --git a/docs/docs/messaging/index.md b/docs/docs/messaging/index.md index 47295287..40be9b88 100644 --- a/docs/docs/messaging/index.md +++ b/docs/docs/messaging/index.md @@ -158,6 +158,7 @@ Once enabled, users see the new "CallMeBot" option when trying to enable messagi - [Signal Messenger](https://www.callmebot.com/blog/free-api-signal-send-messages/) - [Whatsapp](https://www.callmebot.com/blog/free-api-whatsapp-messages/) - [Facebook Messenger](https://www.callmebot.com/blog/free-api-facebook-messenger/) + - [Telegram](https://www.callmebot.com/blog/telegram-text-messages/) Once the user has enabled their account, they can cut & paste the CallMeBot URI into MeshCentral to validate their account. @@ -194,9 +195,24 @@ Once setup, the server will offer users the "Pushover" option when setting up me } } ``` - No setup is reqired to enable this. When using ntfy, make sure you use a suffisently random topic name so that others can't guess the name and subscribe to it to receive your messages. +For [self-hosting your own ntfy server](https://ntfy.sh/docs/install/) with [ACL support](https://ntfy.sh/docs/config/#access-control) + +You can set `host` to the DNS name of your server, `userurl` to the url to provide to users to setup access to your server and `authorization` to the Basic base64 User+Pass authenttication for your server + +```json +{ + "messaging": { + "ntfy": { + "host": "myntfyserver.com", + "userurl": "https://myntfyserver.com/userhelp", + "authorization": "Basic cGhpbDpteXBhc3M=" + } + } +} +``` + ![](images/MC2-Ntfy1.png) ## Zulip setup @@ -206,9 +222,26 @@ You can enable the MeshCentral [Zulip](https://zulip.com/) integration with the ```json { "messaging": { - "site": "https://api.zulip.com", - "email": "your-bot@zulip.com", - "api_key": "your_32_character_api_key" + "zulip": { + "site": "https://api.zulip.com", + "email": "your-bot@zulip.com", + "api_key": "your_32_character_api_key" + } + } +} +``` + +## Slack setup + +[Slack](https://slack.com/) integration is achieved by the use of Incoming Webhooks. +You can get started by following the Slack guide [here](https://api.slack.com/messaging/webhooks) and getting your URL + +Once you have your incoming webhooks url, You can enable the [Slack](https://slack.com/) integration with the following config.json section + +```json +{ + "messaging": { + "slack": true } } ``` @@ -255,4 +288,4 @@ Notice the `msg2factor` is set to false. In this case, messaging can still be us For administrators, login reports will show if "Messaging" was used as a second factor for a user login. You can see this in this report: -![](images/MC2-Telegram4.png) \ No newline at end of file +![](images/MC2-Telegram4.png) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 23285be2..8773ed8a 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -20,6 +20,9 @@ nav: - 'Tokens': 'meshcentral/tokens.md' - 'FAQ': 'meshcentral/faq.md' - 'Tips n Tricks': 'meshcentral/tipsntricks.md' + - 'Messaging': 'messaging/index.md' + - 'Customization': 'meshcentral/customization.md' + - 'openidConnectStrategy': 'meshcentral/openidConnectStrategy.md' - Design and Architecture: - design/index.md @@ -36,13 +39,16 @@ nav: - Intel AMT: - intelamt/index.md + - How to Contribute: + - how-to-contribute/index.md + - Other: - other/adfs_sso_guide.md - other/meshcentral_satellite.md site_description: "A remote monitoring and management tool" site_author: "Ylianst" -site_url: "https://git.meshcentral.com/" +site_url: "https://ylianst.github.io/MeshCentral/" dev_addr: "0.0.0.0:8010" diff --git a/docs/powerpoints/MeshCentral - 0093 - Web Relay Sharing.pptx b/docs/powerpoints/MeshCentral - 0093 - Web Relay Sharing.pptx new file mode 100644 index 00000000..84f78b38 Binary files /dev/null and b/docs/powerpoints/MeshCentral - 0093 - Web Relay Sharing.pptx differ diff --git a/docs/powerpoints/MeshCentral - 0094 - Device Pages.pptx b/docs/powerpoints/MeshCentral - 0094 - Device Pages.pptx new file mode 100644 index 00000000..9900ad68 Binary files /dev/null and b/docs/powerpoints/MeshCentral - 0094 - Device Pages.pptx differ diff --git a/docs/powerpoints/MeshCentral - 0095 - Security Password Policies.pptx b/docs/powerpoints/MeshCentral - 0095 - Security Password Policies.pptx new file mode 100644 index 00000000..cc61a0e7 Binary files /dev/null and b/docs/powerpoints/MeshCentral - 0095 - Security Password Policies.pptx differ diff --git a/emails/translations/account-check_hu.html b/emails/translations/account-check_hu.html new file mode 100644 index 00000000..ee47a1ca --- /dev/null +++ b/emails/translations/account-check_hu.html @@ -0,0 +1,15 @@ +
[[[SERVERNAME]]] - Email megerősítés
+
+ + + + +
+ [[[SERVERNAME]]] - Megerősítés +
+

Tisztelt [[[USERNAME]]], [[[SERVERNAME]]] e-mail megerősítést kér, kattintson az alábbi linkre a folyamat befejezéséhez.

+

+ Kattintson ide az e-mail címének megerősítéséhez. +

+ Ha nem Ön kezdeményezte ezt a kérést, kérjük, hagyja figyelmen kívül ezt a levelet. +
\ No newline at end of file diff --git a/emails/translations/account-check_hu.txt b/emails/translations/account-check_hu.txt new file mode 100644 index 00000000..2e420352 --- /dev/null +++ b/emails/translations/account-check_hu.txt @@ -0,0 +1,6 @@ +[[[SERVERNAME]]] - Email megerősítés +Tisztelt [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]][[[URLARGS1]]]) e-mail ellenőrzést végez. A folyamat befejezéséhez lépjen a következő linkre: +~ +~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]][[[URLARGS2]]] +~ +Ha nem Ön kezdeményezte ezt a kérést, kérjük, hagyja figyelmen kívül ezt a levelet. \ No newline at end of file diff --git a/emails/translations/account-check_zh-chs.html b/emails/translations/account-check_zh-chs.html index 458f9dae..49ebb484 100644 --- a/emails/translations/account-check_zh-chs.html +++ b/emails/translations/account-check_zh-chs.html @@ -1,4 +1,4 @@ -
更改邮件地址
+
[[[SERVERNAME]]] - 邮件验证
@@ -11,5 +11,5 @@

单击此处以验证您的邮件地址。

- 如果您没有发起此请求,请不理此邮件。 + 如果您没有发起此请求,请忽略此邮件。 \ No newline at end of file diff --git a/emails/translations/account-check_zh-chs.txt b/emails/translations/account-check_zh-chs.txt index 95c6ca31..38db4b5b 100644 --- a/emails/translations/account-check_zh-chs.txt +++ b/emails/translations/account-check_zh-chs.txt @@ -1,6 +1,6 @@ -更改邮件地址 +[[[SERVERNAME]]] - 邮件验证 嗨[[[USERNAME]]],[[[SERVERNAME]]] ([[[SERVERURL]]][[[URLARGS1]]]) 正在执行邮件验证。转到以下链接以完成该过程: ~ ~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]][[[URLARGS2]]] ~ -如果您没有发起此请求,请不理此邮件。 \ No newline at end of file +如果您没有发起此请求,请忽略此邮件。 \ No newline at end of file diff --git a/emails/translations/account-invite_hu.html b/emails/translations/account-invite_hu.html new file mode 100644 index 00000000..b6151710 --- /dev/null +++ b/emails/translations/account-invite_hu.html @@ -0,0 +1,19 @@ +
[[[SERVERNAME]]] - Fiók meghívó
+
+
+ + + +
+ [[[SERVERNAME]]] - Fiók meghívó +
+

Létrehozásra került Önnek egy fiók a kiszolgálón [[[SERVERNAME]]], most a következőkkel érheti el:

+

+    Felhasználó név: [[[ACCOUNTNAME]]]
+    Jelszó: [[[PASSWORD]]] +

+ Üdvözlettel, +
+ [[[USERNAME]]] +
+
\ No newline at end of file diff --git a/emails/translations/account-invite_hu.txt b/emails/translations/account-invite_hu.txt new file mode 100644 index 00000000..6b85d933 --- /dev/null +++ b/emails/translations/account-invite_hu.txt @@ -0,0 +1,5 @@ +[[[SERVERNAME]]] - Fiók meghívó +A [[[SERVERNAME]]] szerveren ([[[SERVERURL]]]/[[[URLARGS1]]]) létrehozásra került egy fiókot az Ön számára, amelyhez most már hozzáférhet a "[[[[ACCOUNTNAME]]]" felhasználónévvel és a "[[[[PASSWORD]]]" jelszóval. +~ +Üdvözlettel, +~[[[USERNAME]]] \ No newline at end of file diff --git a/emails/translations/account-invite_pt.html b/emails/translations/account-invite_pt.html index 84d3e9e8..d804ac67 100644 --- a/emails/translations/account-invite_pt.html +++ b/emails/translations/account-invite_pt.html @@ -7,7 +7,7 @@ -

Uma conta foi criada para você no servidor [[[SERVERNAME]]], você pode acessá-lo agora com:

+

Uma conta foi criada para você no servidor [[[SERVERNAME]]], pode aceder agora com:

   Nome de usuário: [[[ACCOUNTNAME]]]
   Senha: [[[PASSWORD]]] diff --git a/emails/translations/account-login_hu.html b/emails/translations/account-login_hu.html new file mode 100644 index 00000000..e8c93ae3 --- /dev/null +++ b/emails/translations/account-login_hu.html @@ -0,0 +1,12 @@ +

[[[SERVERNAME]]] - Bejelentkezés a fiókba
+
+ + + + +
+ [[[SERVERNAME]]] - Bejelentkezés a fiókba +
+

Az Ön bejelentkezési tokenje: [[[TOKEN]]]

+

Ez a token csak egyszer használható, és 5 percig érvényes.

+
\ No newline at end of file diff --git a/emails/translations/account-login_hu.txt b/emails/translations/account-login_hu.txt new file mode 100644 index 00000000..0b104a09 --- /dev/null +++ b/emails/translations/account-login_hu.txt @@ -0,0 +1,4 @@ +[[[SERVERNAME]]] - Bejelentkezés a fiókba +Az Ön bejelentkezési tokenje: [[[TOKEN]]] +~ +Ez a token csak egyszer használható, és 5 percig érvényes. \ No newline at end of file diff --git a/emails/translations/account-reset_hu.html b/emails/translations/account-reset_hu.html new file mode 100644 index 00000000..4d8247d9 --- /dev/null +++ b/emails/translations/account-reset_hu.html @@ -0,0 +1,15 @@ +
[[[SERVERNAME]]] - Fiók visszaállítás
+
+ + + + +
+ [[[SERVERNAME]]] - Megerősítés +
+

Tisztelt [[[USERNAME]]], [[[SERVERNAME]]] fiókhoz tartozó jelszó visszaállítási igényt kapott, kattintson a következő linkre a folyamat befejezéséhez.

+

+ Kattintson ide fiókja jelszaváknak visszaállításához. +

+ Ha nem Ön kezdeményezte ezt a kérést, kérjük, hagyja figyelmen kívül ezt a levelet. +
\ No newline at end of file diff --git a/emails/translations/account-reset_hu.txt b/emails/translations/account-reset_hu.txt new file mode 100644 index 00000000..39f76c76 --- /dev/null +++ b/emails/translations/account-reset_hu.txt @@ -0,0 +1,6 @@ +[[[SERVERNAME]]] - Fiók visszaállítás +Tisztelt [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]][[[URLARGS1]]]) a fiók jelszavának visszaállítását kéri. A folyamat befejezéséhez lépjen a következő linkre: +~ +~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]][[[URLARGS2]]] +~ +Ha nem Ön kezdeményezte ezt a kérést, kérjük, hagyja figyelmen kívül ezt a levelet. \ No newline at end of file diff --git a/emails/translations/account-reset_zh-chs.html b/emails/translations/account-reset_zh-chs.html index e75bd63f..824250dd 100644 --- a/emails/translations/account-reset_zh-chs.html +++ b/emails/translations/account-reset_zh-chs.html @@ -11,5 +11,5 @@

单击此处重置您的帐户密码。

- 如果您没有发起此请求,请不理此邮件。 + 如果您没有发起此请求,请忽略此邮件。 \ No newline at end of file diff --git a/emails/translations/account-reset_zh-chs.txt b/emails/translations/account-reset_zh-chs.txt index 97e9a2b7..8f1e1cb9 100644 --- a/emails/translations/account-reset_zh-chs.txt +++ b/emails/translations/account-reset_zh-chs.txt @@ -3,4 +3,4 @@ ~ ~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]][[[URLARGS2]]] ~ -如果您没有发起此请求,请不理此邮件。 \ No newline at end of file +如果您没有发起此请求,请忽略此邮件。 \ No newline at end of file diff --git a/emails/translations/device-help_cs.html b/emails/translations/device-help_cs.html index 8aee1a99..ca6f8ed6 100644 --- a/emails/translations/device-help_cs.html +++ b/emails/translations/device-help_cs.html @@ -8,7 +8,7 @@

- Device "[[[DEVICENAME]]]" requested help. + Device "[[[DEVICENAME]]]" požádal o pomoc.

User: [[[HELPUSERNAME]]]
diff --git a/emails/translations/device-help_de.html b/emails/translations/device-help_de.html index 9eccab26..7e01917a 100644 --- a/emails/translations/device-help_de.html +++ b/emails/translations/device-help_de.html @@ -8,13 +8,13 @@

- Device "[[[DEVICENAME]]]" requested help. + Gerät "[[[DEVICENAME]]]" requested help.

- User: [[[HELPUSERNAME]]]
- Request: [[[HELPREQUEST]]] + Benutzer: [[[HELPUSERNAME]]]
+ Anforderung: [[[HELPREQUEST]]]

- hier klicken to navigate to this device. + hier klicken um zu diesem Gerät zu navigieren.

\ No newline at end of file diff --git a/emails/translations/device-help_de.txt b/emails/translations/device-help_de.txt index c2b3c09f..849df051 100644 --- a/emails/translations/device-help_de.txt +++ b/emails/translations/device-help_de.txt @@ -1,7 +1,7 @@ [[[SERVERNAME]]] - Device Help Request -Device "[[[DEVICENAME]]]" requested assistance. +Gerät "[[[DEVICENAME]]]" hat Unterstützung angefordert. -User: "[[[HELPUSERNAME]]]" -Request: "[[[HELPREQUEST]]]" +Benutzer: "[[[HELPUSERNAME]]]" +Anforderung: "[[[HELPREQUEST]]]" [[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]] \ No newline at end of file diff --git a/emails/translations/device-help_es.html b/emails/translations/device-help_es.html index fdef26b0..beafbccf 100644 --- a/emails/translations/device-help_es.html +++ b/emails/translations/device-help_es.html @@ -1,20 +1,20 @@ -
[[[SERVERNAME]]] - "[[[DEVICENAME]]]" Help Request
+
[[[SERVERNAME]]] - "[[[DEVICENAME]]]" Solicitud de Ayuda
- [[[SERVERNAME]]] - Help Request + [[[SERVERNAME]]] - Solicitud de Ayuda

- Device "[[[DEVICENAME]]]" requested help. + Dispositivo "[[[DEVICENAME]]]" ha pedido ayuda.

- User: [[[HELPUSERNAME]]]
- Request: [[[HELPREQUEST]]] + Usuario: [[[HELPUSERNAME]]]
+ Solicitud: [[[HELPREQUEST]]]

- haz clic aquí to navigate to this device. + haz clic aquí para navegar a este dispositivo.

\ No newline at end of file diff --git a/emails/translations/device-help_es.txt b/emails/translations/device-help_es.txt index c2b3c09f..3dc02cc3 100644 --- a/emails/translations/device-help_es.txt +++ b/emails/translations/device-help_es.txt @@ -1,7 +1,7 @@ -[[[SERVERNAME]]] - Device Help Request -Device "[[[DEVICENAME]]]" requested assistance. +[[[SERVERNAME]]] - Solicitud de ayuda con el Dispositivo +Dispositivo "[[[DEVICENAME]]]" solicito asistencia. -User: "[[[HELPUSERNAME]]]" -Request: "[[[HELPREQUEST]]]" +Usuario: "[[[HELPUSERNAME]]]" +Solicitud: "[[[HELPREQUEST]]]" [[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]] \ No newline at end of file diff --git a/emails/translations/device-help_fr.html b/emails/translations/device-help_fr.html index d4f9a737..745639b3 100644 --- a/emails/translations/device-help_fr.html +++ b/emails/translations/device-help_fr.html @@ -1,20 +1,20 @@ -
[[[SERVERNAME]]] - "[[[DEVICENAME]]]" Help Request
+
[[[SERVERNAME]]] - "[[[DEVICENAME]]]" Demande d'assistance
- [[[SERVERNAME]]] - Help Request + [[[SERVERNAME]]] - Demande d'assistance

- Device "[[[DEVICENAME]]]" requested help. + Appareil "[[[DEVICENAME]]]" assistance demandée.

- User: [[[HELPUSERNAME]]]
- Request: [[[HELPREQUEST]]] + Utilisateur : [[[HELPUSERNAME]]]
+ Demande : [[[HELPREQUEST]]]

- cliquez ici to navigate to this device. + cliquez ici pour naviguer vers cet appareil.

\ No newline at end of file diff --git a/emails/translations/device-help_fr.txt b/emails/translations/device-help_fr.txt index c2b3c09f..8c08fe7a 100644 --- a/emails/translations/device-help_fr.txt +++ b/emails/translations/device-help_fr.txt @@ -1,7 +1,7 @@ -[[[SERVERNAME]]] - Device Help Request -Device "[[[DEVICENAME]]]" requested assistance. +[[[SERVERNAME]]] - Demande d'assistance sur l'appareil +Une assistance est demandée par l'appareil "[[[DEVICENAME]]]" -User: "[[[HELPUSERNAME]]]" -Request: "[[[HELPREQUEST]]]" +Utilistateur : "[[[HELPUSERNAME]]]" +Demande : "[[[HELPREQUEST]]]" [[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]] \ No newline at end of file diff --git a/emails/translations/device-help_hu.html b/emails/translations/device-help_hu.html new file mode 100644 index 00000000..75f8cb32 --- /dev/null +++ b/emails/translations/device-help_hu.html @@ -0,0 +1,20 @@ +
[[[SERVERNAME]]] - "[[[DEVICENAME]]]" Segítség kérés
+
+ + + + +
+ [[[SERVERNAME]]] - Segítség kérés +
+

+ Eszköz "[[[DEVICENAME]]]" segítséget kért. +

+

+ Felhsználó: [[[HELPUSERNAME]]]
+ Segítségkérés: [[[HELPREQUEST]]] +

+

+ Kattintson ide az eszközhöz való navigáláshoz. +

+
\ No newline at end of file diff --git a/emails/translations/device-help_hu.txt b/emails/translations/device-help_hu.txt new file mode 100644 index 00000000..4dcc6a94 --- /dev/null +++ b/emails/translations/device-help_hu.txt @@ -0,0 +1,7 @@ +[[[SERVERNAME]]] - Segítség kérés +A "[[[DEVICENAME]]]" eszköz segítséget kért. + +Felhasználó: "[[[HELPUSERNAME]]]" +Segítség kérés: "[[[HELPREQUEST]]]" + +[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]] \ No newline at end of file diff --git a/emails/translations/device-notify_cs.html b/emails/translations/device-notify_cs.html index 9bebac77..37b8536e 100644 --- a/emails/translations/device-notify_cs.html +++ b/emails/translations/device-notify_cs.html @@ -1,9 +1,9 @@ -
[[[SERVERNAME]]] – Oznámení zařízení
+
[[[SERVERNAME]]] - Oznámení zařízení
- [[[SERVERNAME]]] – Oznámení zařízení + [[[SERVERNAME]]] - Oznámení zařízení
diff --git a/emails/translations/device-notify_cs.txt b/emails/translations/device-notify_cs.txt index 29d28676..fad0096b 100644 --- a/emails/translations/device-notify_cs.txt +++ b/emails/translations/device-notify_cs.txt @@ -1,4 +1,4 @@ -[[[SERVERNAME]]] – Oznámení zařízení +[[[SERVERNAME]]] - Oznámení zařízení ~ Následující zařízení změnila svůj stav připojení. ~ diff --git a/emails/translations/device-notify_hu.html b/emails/translations/device-notify_hu.html new file mode 100644 index 00000000..556ec224 --- /dev/null +++ b/emails/translations/device-notify_hu.html @@ -0,0 +1,36 @@ +
[[[SERVERNAME]]] - Eszköz értesítés
+
+ + + + +
+ [[[SERVERNAME]]] - Eszköz értesítés +
+ +

+ A következő eszközök kapcsolati állapota megváltozott. +

+
+ +

+ Csatlakozott eszközök: +

+

+[[[CONNECTIONS]]] +

+
+ +

+ Lecsatlakozott eszközök: +

+

+[[[DISCONNECTIONS]]] +

+
+ +

+ A leiratkozáshoz, Kattintson ide az üzenet kézhezvételétől számított 1 órán belül. +

+
+
\ No newline at end of file diff --git a/emails/translations/device-notify_hu.txt b/emails/translations/device-notify_hu.txt new file mode 100644 index 00000000..d025d6a0 --- /dev/null +++ b/emails/translations/device-notify_hu.txt @@ -0,0 +1,22 @@ +[[[SERVERNAME]]] - Eszköz értesítés +~ +A következő eszközök kapcsolati állapota megváltozott. +~ +~ +~ +Csatlakozott eszközök: +~ +~[[[CONNECTIONS]]] +~ +~ +~ +~ +Lecsatlakozott eszközök: +~ +~[[[DISCONNECTIONS]]] +~ +~ +~ + +A leiratkozáshoz lépjen erre a linkre az üzenet kézhezvételétől számított 1 órán belül: [[[SERVERURL]]][[UNSUBSCRIBELINK]]] +~ \ No newline at end of file diff --git a/emails/translations/mesh-invite_hu.html b/emails/translations/mesh-invite_hu.html new file mode 100644 index 00000000..10faaf72 --- /dev/null +++ b/emails/translations/mesh-invite_hu.html @@ -0,0 +1,47 @@ +
[[[SERVERNAME]]] - Meghívás
+
+ + + + +
+ [[[SERVERNAME]]] - Agent Telepítése +
+ +

+ Tisztelt [[[NAME]]], +

+
+

[[[USERNAME]]] felhasználó, kiszolgáló: [[[SERVERNAME]]] kéri hogy telepítse az alkalmazást, amivel lehetőség van távvezérlő munkamant elindítására.

+ +

+ Üzenet: [[[MSG]]] +

+
+ +

+ Kattintson ide a MeshAgent for Windows letöltéséhez. +

+
+ +

Kattintson ide az Apple OSX rendszerhez készült MeshAgent letöltéséhez.

+
+ +

+ Linux esetén az Agent telepítéséhez vágja ki és illessze be egy terminálba a következőt:
+

wget -q "[[[SERVERURL]]]/meshagents?script=1" --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh [[[SERVERURL]]] \'[[[MESHIDHEX]]]\'
+

+
+ +

+ Kattintson ide a MeshCentral Assistant for Windows letöltéséhez. +

+
+ +

+ A szoftver telepítéséhez, Kattintson ide és kövesse az utasításokat. +

+
+

Ha nem Ön kezdeményezte ezt a kérést, kérjük, hagyja figyelmen kívül ezt a levelet.

+ Üdvözlettel,
[[[USERNAME]]]
+
\ No newline at end of file diff --git a/emails/translations/mesh-invite_hu.txt b/emails/translations/mesh-invite_hu.txt new file mode 100644 index 00000000..437028be --- /dev/null +++ b/emails/translations/mesh-invite_hu.txt @@ -0,0 +1,41 @@ +[[[SERVERNAME]]] - Meghívás +~ +Tisztelt [[[NAME]]], +~ +A [[[USERNAME]]] felhasználó a [[[SERVERNAME]]] kiszolgálón ([[[[SERVERURL]]]/[[[URLARGS1]]]) a távvezérlési munkamenet indításához szükséges szoftver telepítését kéri. +~ +~ +Üzenet: [[[MSG]]] +~ +~ +~ +Windows esetén a folyamat befejezéséhez menjen a következő hivatkozásra: +~ +~[[[SERVERURL]]]/meshagents?id=4&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&installflags=[[[INSTALLFLAGS]]] +~ +~ +~ +Apple OSX esetén kattintson az alábbi linkre a folyamat befejezéséhez: +~ +~[[[SERVERURL]]]/meshosxagent?id=16&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&installflags=[[[INSTALLFLAGS]]] +~ +~ +~ +Linux esetén az Agent telepítéséhez vágja ki és illessze be egy terminálba a következőt: +~ +~wget -q "[[[SERVERURL]]]/meshagents?script=1" --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh [[[SERVERURL]]] '[[[MESHIDHEX]]]' +~ +~ +~ +Windows rendszeren futó MeshCentral Assistant esetén menjen a következő hivatkozásra a folyamat befejezéséhez: +~ +~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]] +~ +~ +~ +A szoftver telepítéséhez kérjük lépjen a [[[SERVERURL]]][[[LINKURL]]][[[URLARGS2]]] oldalra, és kövesse az utasításokat. +~ +Ha nem Ön kezdeményezte ezt a kérést, kérjük, hagyja figyelmen kívül ezt a levelet. +~ +Üdvözlettel, +~[[[USERNAME]]] \ No newline at end of file diff --git a/emails/translations/mesh-invite_zh-chs.html b/emails/translations/mesh-invite_zh-chs.html index 733213d6..39b649d5 100644 --- a/emails/translations/mesh-invite_zh-chs.html +++ b/emails/translations/mesh-invite_zh-chs.html @@ -42,6 +42,6 @@ 要安装软件, 点击这里 并按照说明进行操作。

-

如果您没有发起此请求,请不理此邮件。

+

如果您没有发起此请求,请忽略此邮件。

最好的祝福,
[[[USERNAME]]]
\ No newline at end of file diff --git a/emails/translations/mesh-invite_zh-chs.txt b/emails/translations/mesh-invite_zh-chs.txt index 702d65e2..f4140b66 100644 --- a/emails/translations/mesh-invite_zh-chs.txt +++ b/emails/translations/mesh-invite_zh-chs.txt @@ -35,7 +35,7 @@ ~ 要安装软件,请导航至[[[SERVERURL]]][[[LINKURL]]][[[URLARGS2]]],然后按照说明进行操作。 ~ -如果您没有发起此请求,请不理此邮件。 +如果您没有发起此请求,请忽略此邮件。 ~ 最好的祝福, ~[[[USERNAME]]] \ No newline at end of file diff --git a/emails/translations/sms-messages_hu.txt b/emails/translations/sms-messages_hu.txt new file mode 100644 index 00000000..07b75b61 --- /dev/null +++ b/emails/translations/sms-messages_hu.txt @@ -0,0 +1,2 @@ +[[0]] ellenőrző kód: [[1]] +[[0]] hozzáférés token: [[1]] diff --git a/emails/translations/sms-messages_zh-chs.txt b/emails/translations/sms-messages_zh-chs.txt index 92e65ab8..9d2e320e 100644 --- a/emails/translations/sms-messages_zh-chs.txt +++ b/emails/translations/sms-messages_zh-chs.txt @@ -1,2 +1,2 @@ [[0]]验证码是:[[1]] -[[0]]访问保安编码是:[[1]] +[[0]]访问令牌是:[[1]] diff --git a/firebase.js b/firebase.js index d20a9541..124acfa0 100644 --- a/firebase.js +++ b/firebase.js @@ -1,7 +1,6 @@ /** * @description MeshCentral Firebase communication module * @author Ylian Saint-Hilaire -* @copyright Intel Corporation 2018-2022 * @license Apache-2.0 * @version v0.0.1 */ @@ -14,27 +13,31 @@ /*jshint esversion: 6 */ "use strict"; -// Construct the Firebase object -module.exports.CreateFirebase = function (parent, senderid, serverkey) { - var obj = {}; +// Initialize the Firebase Admin SDK +module.exports.CreateFirebase = function (parent, serviceAccount) { + + // Import the Firebase Admin SDK + const admin = require('firebase-admin'); + + const obj = {}; obj.messageId = 0; obj.relays = {}; obj.stats = { - mode: "Real", + mode: 'Real', sent: 0, sendError: 0, received: 0, receivedNoRoute: 0, receivedBadArgs: 0 + }; + + const tokenToNodeMap = {}; // Token --> { nid: nodeid, mid: meshid } + + // Initialize Firebase Admin with server key and project ID + if (!admin.apps.length) { + admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); } - - const Sender = require('node-xcs').Sender; - const Message = require('node-xcs').Message; - const Notification = require('node-xcs').Notification; - const xcs = new Sender(senderid, serverkey); - - var tokenToNodeMap = {} // Token --> { nid: nodeid, mid: meshid } - + // Setup logging if (parent.config.firebase && (parent.config.firebase.log === true)) { obj.logpath = parent.path.join(parent.datapath, 'firebase.txt'); @@ -42,155 +45,108 @@ module.exports.CreateFirebase = function (parent, senderid, serverkey) { } else { obj.log = function () { } } - - // Messages received from client (excluding receipts) - xcs.on('message', function (messageId, from, data, category) { - const jsonData = JSON.stringify(data); - obj.log('Firebase-Message: ' + jsonData); - parent.debug('email', 'Firebase-Message: ' + jsonData); - - if (typeof data.r == 'string') { - // Lookup push relay server - parent.debug('email', 'Firebase-RelayRoute: ' + data.r); - const wsrelay = obj.relays[data.r]; - if (wsrelay != null) { - delete data.r; - try { wsrelay.send(JSON.stringify({ from: from, data: data, category: category })); } catch (ex) { } - } - } else { - // Lookup node information from the cache - var ninfo = tokenToNodeMap[from]; - if (ninfo == null) { obj.stats.receivedNoRoute++; return; } - - if ((data != null) && (data.con != null) && (data.s != null)) { // Console command - obj.stats.received++; - parent.webserver.routeAgentCommand({ action: 'msg', type: 'console', value: data.con, sessionid: data.s }, ninfo.did, ninfo.nid, ninfo.mid); - } else { - obj.stats.receivedBadArgs++; - } - } - }); - - // Only fired for messages where options.delivery_receipt_requested = true - /* - xcs.on('receipt', function (messageId, from, data, category) { console.log('Firebase-Receipt', messageId, from, data, category); }); - xcs.on('connected', function () { console.log('Connected'); }); - xcs.on('disconnected', function () { console.log('disconnected'); }); - xcs.on('online', function () { console.log('online'); }); - xcs.on('error', function (e) { console.log('error', e); }); - xcs.on('message-error', function (e) { console.log('message-error', e); }); - */ - - xcs.start(); - - obj.log('CreateFirebase-Setup'); - parent.debug('email', 'CreateFirebase-Setup'); - - // EXAMPLE - //var payload = { notification: { title: command.title, body: command.msg }, data: { url: obj.msgurl } }; - //var options = { priority: 'High', timeToLive: 5 * 60 }; // TTL: 5 minutes, priority 'Normal' or 'High' - + + // Function to send notifications obj.sendToDevice = function (node, payload, options, func) { - if (typeof node == 'string') { - parent.db.Get(node, function (err, docs) { if ((err == null) && (docs != null) && (docs.length == 1)) { obj.sendToDeviceEx(docs[0], payload, options, func); } else { func(0, 'error'); } }) + if (typeof node === 'string') { + parent.db.Get(node, function (err, docs) { + if (!err && docs && docs.length === 1) { + obj.sendToDeviceEx(docs[0], payload, options, func); + } else { + func(0, 'error'); + } + }); } else { obj.sendToDeviceEx(node, payload, options, func); } - } - + }; + // Send an outbound push notification obj.sendToDeviceEx = function (node, payload, options, func) { - parent.debug('email', 'Firebase-sendToDevice'); - if ((node == null) || (typeof node.pmt != 'string')) return; + if (!node || typeof node.pmt !== 'string') { + func(0, 'error'); + return; + } + obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options)); - + // Fill in our lookup table - if (node._id != null) { tokenToNodeMap[node.pmt] = { nid: node._id, mid: node.meshid, did: node.domain } } - - // Built the on-screen notification - var notification = null; - if (payload.notification) { - var notification = new Notification('ic_message') - .title(payload.notification.title) - .body(payload.notification.body) - .build(); + if (node._id) { + tokenToNodeMap[node.pmt] = { + nid: node._id, + mid: node.meshid, + did: node.domain + }; } - - // Build the message - var message = new Message('msg_' + (++obj.messageId)); - if (options.priority) { message.priority(options.priority); } - if (payload.data) { for (var i in payload.data) { message.addData(i, payload.data[i]); } } - if ((payload.data == null) || (payload.data.shash == null)) { message.addData('shash', parent.webserver.agentCertificateHashBase64); } // Add the server agent hash, new Android agents will reject notifications that don't have this. - if (notification) { message.notification(notification) } - message.build(); - - // Send the message - function callback(result) { - if (result.getError() == null) { obj.stats.sent++; obj.log('Success'); } else { obj.stats.sendError++; obj.log('Fail'); } - callback.func(result.getMessageId(), result.getError(), result.getErrorDescription()) - } - callback.func = func; - parent.debug('email', 'Firebase-sending'); - xcs.sendNoRetry(message, node.pmt, callback); - } - + + const message = { + token: node.pmt, + notification: payload.notification, + data: payload.data, + android: { + priority: options.priority || 'high', + ttl: options.timeToLive ? options.timeToLive * 1000 : undefined + } + }; + + admin.messaging().send(message).then(function (response) { + obj.stats.sent++; + obj.log('Success'); + func(response); + }).catch(function (error) { + obj.stats.sendError++; + obj.log('Fail: ' + error); + func(0, error); + }); + }; + // Setup a two way relay obj.setupRelay = function (ws) { - // Select and set a relay identifier ws.relayId = getRandomPassword(); - while (obj.relays[ws.relayId] != null) { ws.relayId = getRandomPassword(); } + while (obj.relays[ws.relayId]) { ws.relayId = getRandomPassword(); } obj.relays[ws.relayId] = ws; - // On message, parse it ws.on('message', function (msg) { parent.debug('email', 'FBWS-Data(' + this.relayId + '): ' + msg); - if (typeof msg == 'string') { + if (typeof msg === 'string') { obj.log('Relay: ' + msg); - - // Parse the incoming push request - var data = null; - try { data = JSON.parse(msg) } catch (ex) { return; } - if (typeof data != 'object') return; - if (parent.common.validateObjectForMongo(data, 4096) == false) return; // Perform sanity checking on this object. - if (typeof data.pmt != 'string') return; - if (typeof data.payload != 'object') return; - if (typeof data.payload.notification == 'object') { - if (typeof data.payload.notification.title != 'string') return; - if (typeof data.payload.notification.body != 'string') return; - } - if (typeof data.options != 'object') return; - if ((data.options.priority != 'Normal') && (data.options.priority != 'High')) return; - if ((typeof data.options.timeToLive != 'number') || (data.options.timeToLive < 1)) return; - if (typeof data.payload.data != 'object') { data.payload.data = {}; } - data.payload.data.r = ws.relayId; // Set the relay id. - - // Send the push notification - obj.sendToDevice({ pmt: data.pmt }, data.payload, data.options, function (id, err, errdesc) { - if (err == null) { - try { wsrelay.send(JSON.stringify({ sent: true })); } catch (ex) { } + + let data; + try { data = JSON.parse(msg); } catch (ex) { return; } + if (typeof data !== 'object') return; + if (!parent.common.validateObjectForMongo(data, 4096)) return; + if (typeof data.pmt !== 'string' || typeof data.payload !== 'object') return; + + data.payload.data = data.payload.data || {}; + data.payload.data.r = ws.relayId; + + obj.sendToDevice({ pmt: data.pmt }, data.payload, data.options, function (id, err) { + if (!err) { + try { ws.send(JSON.stringify({ sent: true })); } catch (ex) { } } else { - try { wsrelay.send(JSON.stringify({ sent: false })); } catch (ex) { } + try { ws.send(JSON.stringify({ sent: false })); } catch (ex) { } } }); } }); - + // If error, close the relay ws.on('error', function (err) { parent.debug('email', 'FBWS-Error(' + this.relayId + '): ' + err); delete obj.relays[this.relayId]; }); - + // Close the relay ws.on('close', function () { parent.debug('email', 'FBWS-Close(' + this.relayId + ')'); delete obj.relays[this.relayId]; }); - + }; + + function getRandomPassword() { + return Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').replace(/\//g, '@'); } - - function getRandomPassword() { return Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } - + return obj; }; @@ -212,7 +168,7 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { const querystring = require('querystring'); const relayUrl = require('url').parse(url); parent.debug('email', 'CreateFirebaseRelay-Setup'); - + // Setup logging if (parent.config.firebaserelay && (parent.config.firebaserelay.log === true)) { obj.logpath = parent.path.join(parent.datapath, 'firebaserelay.txt'); @@ -220,7 +176,7 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { } else { obj.log = function () { } } - + obj.log('Starting relay to: ' + relayUrl.href); if (relayUrl.protocol == 'wss:') { // Setup two-way push notification channel @@ -252,7 +208,7 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { parent.debug('email', 'FBWS-Disconnected'); obj.wsclient = null; obj.wsopen = false; - + // Compute the backoff timer if (obj.reconnectTimer == null) { if ((obj.lastConnect != null) && ((Date.now() - obj.lastConnect) > 10000)) { obj.backoffTimer = 0; } @@ -263,12 +219,12 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { } }); } - + function processMessage(messageId, from, data, category) { // Lookup node information from the cache var ninfo = obj.tokenToNodeMap[from]; if (ninfo == null) { obj.stats.receivedNoRoute++; return; } - + if ((data != null) && (data.con != null) && (data.s != null)) { // Console command obj.stats.received++; parent.webserver.routeAgentCommand({ action: 'msg', type: 'console', value: data.con, sessionid: data.s }, ninfo.did, ninfo.nid, ninfo.mid); @@ -276,7 +232,7 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { obj.stats.receivedBadArgs++; } } - + obj.sendToDevice = function (node, payload, options, func) { if (typeof node == 'string') { parent.db.Get(node, function (err, docs) { if ((err == null) && (docs != null) && (docs.length == 1)) { obj.sendToDeviceEx(docs[0], payload, options, func); } else { func(0, 'error'); } }) @@ -284,19 +240,19 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { obj.sendToDeviceEx(node, payload, options, func); } } - + obj.sendToDeviceEx = function (node, payload, options, func) { parent.debug('email', 'Firebase-sendToDevice-webSocket'); if ((node == null) || (typeof node.pmt != 'string')) { func(0, 'error'); return; } obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options)); - + // Fill in our lookup table if (node._id != null) { obj.tokenToNodeMap[node.pmt] = { nid: node._id, mid: node.meshid, did: node.domain } } - + // Fill in the server agent cert hash if (payload.data == null) { payload.data = {}; } if (payload.data.shash == null) { payload.data.shash = parent.webserver.agentCertificateHashBase64; } // Add the server agent hash, new Android agents will reject notifications that don't have this. - + // If the web socket is open, send now if (obj.wsopen == true) { try { obj.wsclient.send(JSON.stringify({ pmt: node.pmt, payload: payload, options: options })); } catch (ex) { func(0, 'error'); obj.stats.sendError++; return; } @@ -314,7 +270,7 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { } else if (relayUrl.protocol == 'https:') { // Send an outbound push notification using an HTTPS POST obj.pushOnly = true; - + obj.sendToDevice = function (node, payload, options, func) { if (typeof node == 'string') { parent.db.Get(node, function (err, docs) { if ((err == null) && (docs != null) && (docs.length == 1)) { obj.sendToDeviceEx(docs[0], payload, options, func); } else { func(0, 'error'); } }) @@ -322,18 +278,18 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { obj.sendToDeviceEx(node, payload, options, func); } } - + obj.sendToDeviceEx = function (node, payload, options, func) { parent.debug('email', 'Firebase-sendToDevice-httpPost'); if ((node == null) || (typeof node.pmt != 'string')) return; - + // Fill in the server agent cert hash if (payload.data == null) { payload.data = {}; } if (payload.data.shash == null) { payload.data.shash = parent.webserver.agentCertificateHashBase64; } // Add the server agent hash, new Android agents will reject notifications that don't have this. - + obj.log('sendToDevice, node:' + node._id + ', payload: ' + JSON.stringify(payload) + ', options: ' + JSON.stringify(options)); const querydata = querystring.stringify({ 'msg': JSON.stringify({ pmt: node.pmt, payload: payload, options: options }) }); - + // Send the message to the relay const httpOptions = { hostname: relayUrl.hostname, @@ -357,6 +313,6 @@ module.exports.CreateFirebaseRelay = function (parent, url, key) { req.end(); } } - + return obj; }; \ No newline at end of file diff --git a/interceptor.js b/interceptor.js index 7585620e..c6e4a878 100644 --- a/interceptor.js +++ b/interceptor.js @@ -395,7 +395,7 @@ module.exports.CreateRedirInterceptor = function (args) { if (obj.amt.digestRealm) { // Replace this authentication digest with a server created one // We have everything we need to authenticate - var nc = obj.ws.authCNonceCount; + var nc = '0'+ (10000000 + obj.ws.authCNonceCount).toString().substring(1);// set NC at least 8 bytes obj.ws.authCNonceCount++; var digest = obj.ComputeDigesthash(obj.args.user, obj.args.pass, obj.amt.digestRealm, 'POST', authurl, obj.amt.digestQOP, obj.amt.digestNonce, nc, obj.ws.authCNonce); diff --git a/letsencrypt.js b/letsencrypt.js index c83cf102..c1823ba4 100644 --- a/letsencrypt.js +++ b/letsencrypt.js @@ -28,6 +28,8 @@ module.exports.CreateLetsEncrypt = function (parent) { obj.challenges = {}; obj.runAsProduction = false; obj.redirWebServerHooked = false; + obj.zerossl = false; + obj.csr = null; obj.configErr = null; obj.configOk = false; obj.pendingRequest = false; @@ -57,6 +59,7 @@ module.exports.CreateLetsEncrypt = function (parent) { // Get the current certificate obj.getCertificate = function(certs, func) { obj.runAsProduction = (obj.parent.config.letsencrypt.production === true); + obj.zerossl = ((typeof obj.parent.config.letsencrypt.zerossl == 'object') ? obj.parent.config.letsencrypt.zerossl : false); obj.log("Getting certs from local store (" + (obj.runAsProduction ? "Production" : "Staging") + ")"); if (certs.CommonName.indexOf('.') == -1) { obj.configErr = "Add \"cert\" value to settings in config.json before using Let's Encrypt."; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; } if (obj.parent.config.letsencrypt == null) { obj.configErr = "No Let's Encrypt configuration"; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; } @@ -164,26 +167,36 @@ module.exports.CreateLetsEncrypt = function (parent) { obj.log("Generating private key..."); acme.forge.createPrivateKey().then(function (accountKey) { - // TODO: ZeroSSL - // https://acme.zerossl.com/v2/DV90 - // Create the ACME client obj.log("Setting up ACME client..."); - obj.client = new acme.Client({ - directoryUrl: obj.runAsProduction ? acme.directory.letsencrypt.production : acme.directory.letsencrypt.staging, - accountKey: accountKey - }); + if (obj.zerossl) { + if (obj.zerossl.kid == "") { obj.log("EAB KID hasn't been set, invalid configuration."); return; } + if (obj.zerossl.hmackey == "") { obj.log("EAB HMAC KEY hasn't been set, invalid configuration."); return; } + obj.client = new acme.Client({ + directoryUrl: acme.directory.zerossl.production, + accountKey: accountKey, + externalAccountBinding: { + kid: obj.zerossl.kid, + hmacKey: obj.zerossl.hmackey + } + }); + } else { + obj.client = new acme.Client({ + directoryUrl: obj.runAsProduction ? acme.directory.letsencrypt.production : acme.directory.letsencrypt.staging, + accountKey: accountKey + }); + } // Create Certificate Request (CSR) obj.log("Creating certificate request..."); var certRequest = { commonName: obj.leDomains[0] }; if (obj.leDomains.length > 1) { certRequest.altNames = obj.leDomains; } acme.forge.createCsr(certRequest).then(function (r) { - var csr = r[1]; + obj.csr = r[1]; obj.tempPrivateKey = r[0]; - obj.log("Requesting certificate from Let's Encrypt..."); + if(obj.zerossl) { obj.log("Requesting certificate from ZeroSSL..."); } else { obj.log("Requesting certificate from Let's Encrypt..."); } obj.client.auto({ - csr, + csr: obj.csr, email: obj.parent.config.letsencrypt.email, termsOfServiceAgreed: true, skipChallengeVerification: (obj.parent.config.letsencrypt.skipchallengeverification === true), diff --git a/mcrec.js b/mcrec.js index 565062a9..43966b88 100644 --- a/mcrec.js +++ b/mcrec.js @@ -13,27 +13,15 @@ var worker = null; const NodeJSVer = Number(process.version.match(/^v(\d+\.\d+)/)[1]); var directRun = (require.main === module); function log() { if (directRun) { console.log(...arguments); } /*else { if (worker != null) { worker.parentPort.postMessage({ msg: arguments[0] }); } } */ } +function log2() { if (directRun) { console.log(...arguments); } else { process.send(...arguments); } /*else { if (worker != null) { worker.parentPort.postMessage({ msg: arguments[0] }); } } */ } if (directRun && (NodeJSVer >= 12)) { const xworker = require('worker_threads'); try { if (xworker.isMainThread == false) { worker = xworker; } } catch (ex) { log(ex); } } -function start() { startEx(process.argv); } -if (directRun) { setup(); } - -function setup() { InstallModules(['image-size'], start); } -function start() { startEx(process.argv); } -function startEx(argv) { - if (argv.length > 2) { indexFile(argv[2]); } else { - log("MeshCentral Session Recodings Processor"); - log("This tool will index a .mcrec file so that the player can seek thru the file."); - log(""); - log(" Usage: node mcrec [file]"); - } -} function indexFile(infile) { var state = { recFileName: null, recFile: null, recFileSize: 0, recFilePtr: 0 }; - if (fs.existsSync(infile) == false) { log("Missing file: " + infile); return; } + if (fs.existsSync(infile) == false) { log2("Missing file: " + infile); return; } state.recFileName = infile; state.recFileSize = fs.statSync(infile).size; - if (state.recFileSize < 32) { log("Invalid file: " + infile); return; } + if (state.recFileSize < 32) { log2("Invalid file size: " + infile); return; } log("Processing file: " + infile + ", " + state.recFileSize + " bytes."); state.recFile = fs.openSync(infile, 'r+'); state.indexTime = 10; // Interval between indexes in seconds @@ -43,8 +31,8 @@ function indexFile(infile) { state.height = 0; state.basePtr = null; readLastBlock(state, function (state, result, time, extras) { - if (result == false) { log("Invalid file: " + infile); return; } - if (extras != null) { log("File already indexed: " + infile); return; } + if (result == false) { log2("Invalid file: " + infile); return; } + if (extras != null) { log2("File already indexed: " + infile); return; } state.lastTimeStamp = time; readNextBlock(state, processBlock); }); @@ -68,7 +56,7 @@ function processBlock(state, block, err) { // Error reading the next block, exit now. fs.close(state.recFile, function () { for (var i in state) { delete state[i]; } // Clear the state. - log("Error."); + log2("Error."); }); return; } @@ -77,7 +65,7 @@ function processBlock(state, block, err) { writeIndex(state, function () { fs.close(state.recFile, function () { for (var i in state) { delete state[i]; } // Clear the state. - log("Done."); + log2("Done."); }); }); return; @@ -96,8 +84,8 @@ function processBlock(state, block, err) { if (block.type == 1) { // Metadata state.metadata = JSON.parse(block.data.toString()); - if (state.metadata.indexInterval != null) { log("This file is already indexed."); return; } - if (state.metadata.protocol != 2) { log("Only remote desktop sessions can currently be indexed."); return; } + if (state.metadata.indexInterval != null) { log2("This file is already indexed."); return; } + if (state.metadata.protocol != 2) { log2("Only remote desktop sessions can currently be indexed."); return; } state.metadataFlags = block.flags; state.metadataTime = block.time; state.recFileProtocol = state.metadata.protocol; @@ -316,7 +304,7 @@ function InstallModule(modulename, func, tag1, tag2) { if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); } // Looks like we need to keep a global reference to the child process object for this to work correctly. - InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) { + InstallModuleChildProcess = child_process.exec('npm install --no-optional --save ' + modulename, { maxBuffer: 512000, timeout: 300000, cwd: parentpath }, function (error, stdout, stderr) { InstallModuleChildProcess = null; if ((error != null) && (error != '')) { log('ERROR: Unable to install required module "' + modulename + '". May not have access to npm, or npm may not have suffisent rights to load the new module. Try "npm install ' + modulename + '" to manualy install this module.\r\n'); @@ -329,6 +317,18 @@ function InstallModule(modulename, func, tag1, tag2) { }); } +function setup() { InstallModules(['image-size'], start); } +function start() { startEx(process.argv); } +function startEx(argv) { + if (argv.length > 2) { indexFile(argv[2]); } else { + log("MeshCentral Session Recordings Processor"); + log("This tool will index a .mcrec file so that the player can seek thru the file."); + log(""); + log(" Usage: node mcrec [file]"); + } +} +if (directRun) { setup(); } + // Export table module.exports.startEx = startEx; module.exports.indexFile = indexFile; \ No newline at end of file diff --git a/meshaccelerator.js b/meshaccelerator.js index c492f92b..5e663383 100644 --- a/meshaccelerator.js +++ b/meshaccelerator.js @@ -32,7 +32,20 @@ module.exports.processMessage = function(message) { const sign = crypto.createSign('SHA384'); sign.end(Buffer.from(message.data, 'binary')); process.send(sign.sign(message.key).toString('binary')); - } catch (e) { process.send(null); } + } catch (ex) { + // If this exception happens, try again. + if (ex.code == 'ERR_OSSL_DSO_COULD_NOT_LOAD_THE_SHARED_LIBRARY') { + try { + const sign = crypto.createSign('SHA384'); + sign.end(Buffer.from(message.data, 'binary')); + process.send(sign.sign(message.key).toString('binary')); + } catch (ex) { + process.send(null); + } + } else { + process.send(null); + } + } break; } case 'setState': { diff --git a/meshagent.js b/meshagent.js index 88c0b01f..7169b9ff 100644 --- a/meshagent.js +++ b/meshagent.js @@ -58,15 +58,15 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { dataAccounting(); if ((arg == 1) || (arg == null)) { try { ws.close(); if (obj.nodeid != null) { parent.parent.debug('agent', 'Soft disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Soft close, close the websocket - if (arg == 2) { - try { + if (arg == 2) { + try { if (ws._socket._parent != null) ws._socket._parent.end(); else ws._socket.end(); - - if (obj.nodeid != null) { - parent.parent.debug('agent', 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); + + if (obj.nodeid != null) { + parent.parent.debug('agent', 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } @@ -616,7 +616,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { } if ((mesh == null) && (typeof domain.orphanagentuser == 'string')) { - const adminUser = parent.users['user/' + domain.id + '/' + domain.orphanagentuser.toLowerCase()]; + const adminUser = parent.users['user/' + domain.id + '/' + domain.orphanagentuser]; if ((adminUser != null) && (adminUser.siteadmin == 0xFFFFFFFF)) { // Mesh name is hex instead of base64 const meshname = obj.meshid.substring(0, 18); @@ -1058,7 +1058,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { db.Get('iploc_' + obj.remoteaddr, function (err, iplocs) { if ((iplocs != null) && (iplocs.length == 1)) { // We have a location in the database for this remote IP - const iploc = nodes[0], x = {}; + const iploc = iplocs[0], x = {}; if ((iploc != null) && (iploc.ip != null) && (iploc.loc != null)) { x.publicip = iploc.ip; x.iploc = iploc.loc + ',' + (Math.floor((new Date(iploc.date)) / 1000)); @@ -1067,10 +1067,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { } else { // Check if we need to ask for the IP location var doIpLocation = 0; - if (device.iploc == null) { + if (obj.iploc == null) { doIpLocation = 1; } else { - const loc = device.iploc.split(','); + const loc = obj.iploc.split(','); if (loc.length < 3) { doIpLocation = 2; } else { @@ -1920,6 +1920,14 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { if (!device.wsc) { device.wsc = {}; } if (JSON.stringify(device.wsc) != JSON.stringify(command.wsc)) { /*changes.push('Windows Security Center status');*/ device.wsc = command.wsc; change = 1; log = 1; } } + if (command.defender != null) { // Defender For Windows Server + if (!device.defender) { device.defender = {}; } + if (JSON.stringify(device.defender) != JSON.stringify(command.defender)) { /*changes.push('Defender status');*/ device.defender = command.defender; change = 1; log = 1; } + } + if (command.lastbootuptime != null) { // Last Boot Up Time + if (!device.lastbootuptime) { device.lastbootuptime = ""; } + if (device.lastbootuptime != command.lastbootuptime) { /*changes.push('Last Boot Up Time');*/ device.lastbootuptime = command.lastbootuptime; change = 1; log = 1; } + } // Push Messaging Token if ((command.pmt != null) && (typeof command.pmt == 'string') && (device.pmt != command.pmt)) { @@ -1928,14 +1936,18 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { change = 1; // Don't save this change as an event to the db, so no log=1. parent.removePmtFromAllOtherNodes(device); // We need to make sure to remove this push messaging token from any other device on this server, all domains included. } - + if ((command.users != null) && (Array.isArray(command.users)) && (device.users != command.users)) { device.users = command.users; change = 1; } // Don't save this to the db. + if ((command.lusers != null) && (Array.isArray(command.lusers)) && (device.lusers != command.lusers)) { device.lusers = command.lusers; change = 1; } // Don't save this to the db. if ((mesh.mtype == 2) && (!args.wanonly)) { // In WAN mode, the hostname of a computer is not important. Don't log hostname changes. if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); } // TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match. } + // Remove old volumes and BitLocker data, this is part of sysinfo. + delete device.volumes; + // If there are changes, event the new device if (change == 1) { // Do some clean up if needed, these values should not be in the database. diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index b6edad3a..91cec3b8 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -3,58 +3,183 @@ "$schema": "http://json-schema.org/draft-04/schema#", "description": "MeshCentral configuration file schema", "type": "object", + "required": [ + "settings", + "domains" + ], "properties": { "settings": { "type": "object", "properties": { - "cert": { "type": "string", "description": "Set this to the primary DNS name of this MeshCentral server." }, - "keepCerts": { "type": "boolean", "default": false, "description": "Force MeshCentral to use the HTTPS and MPS certificates even if the name does not match the expected DNS value." }, - "mongoDb": { "type": "string", "default": null }, - "mongoDbName": { "type": "string" }, - "mongoDbChangeStream": { "type": "boolean", "default": false }, - "mongoDbBulkOperations": { "type": "boolean", "default": false }, + "cert": { + "type": "string", + "description": "Set this to the primary DNS name of this MeshCentral server." + }, + "keepCerts": { + "type": "boolean", + "default": false, + "description": "Force MeshCentral to use the HTTPS and MPS certificates even if the name does not match the expected DNS value." + }, + "mongoDb": { + "type": "string", + "default": null + }, + "mongoDbName": { + "type": "string" + }, + "mongoDbChangeStream": { + "type": "boolean", + "default": false + }, + "mongoDbBulkOperations": { + "type": "boolean", + "default": false + }, "mariaDB": { "type": "object", "description": "Add this section to connect MeshCentral to a MariaDB database instance.", "properties": { - "host": { "type": "string", "description": "MariaDB hostname" }, - "user": { "type": "string", "description": "MariaDB username" }, - "port": { "type": "number", "description": "MariaDB port number" }, - "password": { "type": "string", "description": "MariaDB password" }, - "connectionLimit": { "type": "number", "description": "MariaDB connection limit" }, - "database": { "type": "string", "default": "meshcentral", "description": "Name of MariaDB database used" }, - "awsrds": { "type": "boolean", "default": false, "description": "Set true to resolve LOCK TABLE permissions on AWS RDS." }, - "ssl": { - "type": "object", - "description": "SSL Options. Set to true (boolean) for default options.", - "properties": { - "caCertPath": { "type": "string", "description": "Absolute path to the CA certificate. Required for self-signed certificates" }, - "clientCertPath": { "type": "string", "description": "Absolute path to the client certificate. Required for two-way SSL Authentication" }, - "clientKeyPath": { "type": "string", "description": "Absolute path to the client key. Required for two-way SSL Authentication" }, - "dontCheckServerIdentity": { "type": "boolean", "description": "Set true to not check the server hostname during verification" } - } - } - } - }, - "sqlite3": { "type": "boolean", "default": false, "description": "Set true to use SQLite3 as a local MeshCentral database." }, - "mySQL": { - "type": "object", - "description": "Add this section to connect MeshCentral to a MySQL database instance.", - "properties": { - "host": { "type": "string", "description": "MySQL hostname" }, - "port": { "type": "number", "description": "MySQL port number" }, - "user": { "type": "string", "description": "MySQL username" }, - "password": { "type": "string", "description": "MySQL password" }, - "database": { "type": "string", "default": "meshcentral", "description": "Name of MySQL database used" }, - "awsrds": { "type": "boolean", "default": false, "description": "Set true to resolve LOCK TABLE permissions on AWS RDS." }, + "host": { + "type": "string", + "description": "MariaDB hostname" + }, + "user": { + "type": "string", + "description": "MariaDB username" + }, + "port": { + "type": "number", + "description": "MariaDB port number" + }, + "password": { + "type": "string", + "description": "MariaDB password" + }, + "connectionLimit": { + "type": "number", + "description": "MariaDB connection limit" + }, + "database": { + "type": "string", + "default": "meshcentral", + "description": "Name of MariaDB database used" + }, + "awsrds": { + "type": "boolean", + "default": false, + "description": "Set true to resolve LOCK TABLE permissions on AWS RDS." + }, "ssl": { "type": "object", "description": "SSL Options. Set to true (boolean) for default options.", "properties": { - "caCertPath": { "type": "string", "description": "Absolute path to the CA certificate. Required for self-signed certificates" }, - "clientCertPath": { "type": "string", "description": "Absolute path to the client certificate. Required for two-way SSL Authentication" }, - "clientKeyPath": { "type": "string", "description": "Absolute path to the client key. Required for two-way SSL Authentication" }, - "dontCheckServerIdentity": { "type": "boolean", "description": "Set true to not check the server hostname during verification" } + "caCertPath": { + "type": "string", + "description": "Absolute path to the CA certificate. Required for self-signed certificates" + }, + "clientCertPath": { + "type": "string", + "description": "Absolute path to the client certificate. Required for two-way SSL Authentication" + }, + "clientKeyPath": { + "type": "string", + "description": "Absolute path to the client key. Required for two-way SSL Authentication" + }, + "dontCheckServerIdentity": { + "type": "boolean", + "description": "Set true to not check the server hostname during verification" + } + } + } + } + }, + "sqlite3": { + "type": [ "boolean", "string", "object" ], + "default": false, + "description": "Set boolean true to use SQLite3 as a local MeshCentral database with default db filename 'meshcentral' or enter a string for a different db filename. Extension .sqlite is appended", + "properties":{ + "name": { + "type": "string", + "default": "meshcentral", + "description": "Database filename. '.sqlite' is appended" + }, + "journalMode": { + "type": "string", + "default": "delete", + "description": "DELETE, TRUNCATE, PERSIST, MEMORY, WAL. NONE not allowed. See: https://www.sqlite.org/pragma.html#pragma_journal_mode" + }, + "journalSize": { + "type": "integer", + "default": 4096000, + "description": "Maximum size of the journal file in bytes. Can grow larger if needed, but will shrink to this size. -1 is unlimited growth. See: https://www.sqlite.org/pragma.html#pragma_journal_size_limit" + }, + "autoVacuum": { + "type": "string", + "default": "incremental", + "description": "none, full, incremental. Removes unused pages and shrinks databasefile during maintenance. See: https://www.sqlite.org/pragma.html#pragma_auto_vacuum" + }, + "incrementalVacuum": { + "type": "integer", + "default": 100, + "description": "Maximum amount of pages to free during maintenance. Default page size is 4k, so default frees up to 400k from the databasefile. See: https://www.sqlite.org/pragma.html#pragma_incremental_vacuum" + }, + "startupVacuum": { + "type": "boolean", + "default": false, + "description": "Do a full VACUUM at startup. Shrinks the db file and optimizes it. This can take some time with a large database and can temporarily take up to double the database size on disk. See: https://www.sqlite.org/lang_vacuum.html" + } + } + }, + "mySQL": { + "type": "object", + "description": "Add this section to connect MeshCentral to a MySQL database instance.", + "properties": { + "host": { + "type": "string", + "description": "MySQL hostname" + }, + "port": { + "type": "number", + "description": "MySQL port number" + }, + "user": { + "type": "string", + "description": "MySQL username" + }, + "password": { + "type": "string", + "description": "MySQL password" + }, + "database": { + "type": "string", + "default": "meshcentral", + "description": "Name of MySQL database used" + }, + "awsrds": { + "type": "boolean", + "default": false, + "description": "Set true to resolve LOCK TABLE permissions on AWS RDS." + }, + "ssl": { + "type": "object", + "description": "SSL Options. Set to true (boolean) for default options.", + "properties": { + "caCertPath": { + "type": "string", + "description": "Absolute path to the CA certificate. Required for self-signed certificates" + }, + "clientCertPath": { + "type": "string", + "description": "Absolute path to the client certificate. Required for two-way SSL Authentication" + }, + "clientKeyPath": { + "type": "string", + "description": "Absolute path to the client key. Required for two-way SSL Authentication" + }, + "dontCheckServerIdentity": { + "type": "boolean", + "description": "Set true to not check the server hostname during verification" + } } } } @@ -63,165 +188,755 @@ "type": "object", "description": "Add this section to connect MeshCentral to a PostgreSQL database instance.", "properties": { - "host": { "type": "string", "description": "PostgreSQL hostname" }, - "user": { "type": "string", "description": "PostgreSQL username" }, - "port": { "type": "number", "description": "PostgreSQL port number" }, - "password": { "type": "string", "description": "PostgreSQL password" }, - "database": { "type": "string", "default": "meshcentral", "description": "Name of PostgreSQL database used" } + "host": { + "type": "string", + "description": "PostgreSQL hostname" + }, + "user": { + "type": "string", + "description": "PostgreSQL username" + }, + "port": { + "type": "number", + "description": "PostgreSQL port number" + }, + "password": { + "type": "string", + "description": "PostgreSQL password" + }, + "database": { + "type": "string", + "default": "meshcentral", + "description": "Name of PostgreSQL database used" + } } }, "acebase": { "type": "object", "description": "Add this section to enable AceBase database support, this is a local database system much like NeDB.", - "properties": { "sponsor": { "type": "boolean", "default": false, "description": "Set true to remove the AceBase banner on startup." } } + "properties": { + "sponsor": { + "type": "boolean", + "default": false, + "description": "Set true to remove the AceBase banner on startup." + } + } + }, + "WANonly": { + "type": "boolean", + "default": false, + "description": "When enabled, only MeshCentral WAN features are enabled and agents will connect to the server using a well known DNS name." + }, + "LANonly": { + "type": "boolean", + "default": false, + "description": "When enabled, only MeshCentral LAN features are enabled and agents will find the server using multicast LAN packets." + }, + "maintenanceMode": { + "type": "boolean", + "default": false, + "description": "When enabled the server is in maintenance mode, only administrators can login. Use the maintenance command in server console to change." + }, + "certificatePrivateKeyPassword": { + "type": "array", + "default": null, + "description": "List of passwords used to decrypt PKCK#8 .key files that are in the meshcentral-data folder." + }, + "sessionTime": { + "type": "integer", + "default": 60, + "description": "Duration of a session cookie in minutes. Changing this affects how often the session needs to be automatically refreshed." + }, + "sessionKey": { + "type": "string", + "default": null, + "description": "Password used to encrypt the MeshCentral web session cookies. If null, a random one is generated each time the server starts." + }, + "sessionSameSite": { + "type": "string", + "default": "lax", + "enum": [ + "strict", + "lax", + "none" + ] + }, + "dbEncryptKey": { + "type": "string", + "default": null, + "description": "This value is only valid when used with NeDB, sets the database encryption and decryption key." + }, + "dbRecordsEncryptKey": { + "type": "string", + "default": null, + "description": "With any database, encrypt and decrypt sensitive information within records using this secret key." + }, + "dbRecordsDecryptKey": { + "type": "string", + "default": null, + "description": "With any database, decrypt sensitive information within records using this secret key, don't use a key to encrypt records." }, - "WANonly": { "type": "boolean", "default": false, "description": "When enabled, only MeshCentral WAN features are enabled and agents will connect to the server using a well known DNS name." }, - "LANonly": { "type": "boolean", "default": false, "description": "When enabled, only MeshCentral LAN features are enabled and agents will find the server using multicast LAN packets." }, - "maintenanceMode": { "type": "boolean", "default": false, "description": "When enabled the server is in maintenance mode, only administrators can login. Use the maintenance command in server console to change." }, - "certificatePrivateKeyPassword": { "type": "array", "default": null, "description": "List of passwords used to decrypt PKCK#8 .key files that are in the meshcentral-data folder." }, - "sessionTime": { "type": "integer", "default": 60, "description": "Duration of a session cookie in minutes. Changing this affects how often the session needs to be automatically refreshed." }, - "sessionKey": { "type": "string", "default": null, "description": "Password used to encrypt the MeshCentral web session cookies. If null, a random one is generated each time the server starts." }, - "sessionSameSite": { "type": "string", "default": "lax", "enum": ["strict", "lax", "none"] }, - "dbEncryptKey": { "type": "string", "default": null, "description": "This value is only valid when used with NeDB, sets the database encryption and decryption key." }, - "dbRecordsEncryptKey": { "type": "string", "default": null, "description": "With any database, encrypt and decrypt sensitive information within records using this secret key." }, - "dbRecordsDecryptKey": { "type": "string", "default": null, "description": "With any database, decrypt sensitive information within records using this secret key, don't use a key to encrypt records." }, "dbExpire": { "type": "object", "properties": { - "events": { "type": "integer", "default": 1728000, "description": "Amount of time in seconds that events are kept in the database." }, - "powerevents": { "type": "integer", "default": 864000, "description": "Amount of time in seconds that device power events are kept in the database." }, - "statsevents": { "type": "integer", "default": 2592000, "description": "Amount of time in seconds that server statistics are kept in the database." } + "events": { + "type": "integer", + "default": 1728000, + "description": "Amount of time in seconds that events are kept in the database." + }, + "powerevents": { + "type": "integer", + "default": 864000, + "description": "Amount of time in seconds that device power events are kept in the database." + }, + "statsevents": { + "type": "integer", + "default": 2592000, + "description": "Amount of time in seconds that server statistics are kept in the database." + } } }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 443, "description": "Ths port of the main HTTPS server." }, - "portBind": { "type": "string", "description": "When set, bind the HTTPS main port to a specific network address." }, - "aliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null, "description": "The actual main port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." }, - "redirPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 80, "description": "This is a HTTP web server port that mostly redirects users to the HTTPS port but does provide some other services, 0 will turn this port off." }, - "redirPortBind": { "type": "string", "description": "When set, bind the HTTP redirection port to a specific network address." }, - "redirAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "The actual redirection port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." }, - "relayPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 0, "description": "When set, a web relay web server is bound to this port and will allow user access to remote web sites." }, - "relayAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null, "description": "The actual relay port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." }, - "relayDNS": { "type": "string", "default": null, "description": "When set, relayPort value is ignored. Set this to a DNS name the points to this server. When the server is accessed using the DNS name, the main web server port is used as a web relay port." }, - "agentPort": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "When set, enabled a new HTTPS server port that only accepts agent connections." }, - "agentPortBind": { "type": "string", "description": "When set, binds the agent port to a specific network interface." }, - "agentAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "When set, indicates the actual publicly visible agent-only port. If not set, the AgentPort value is used." }, - "agentAliasDNS": { "type": "string", "format": "hostname", "description": "When set, specified the DNS name used by agents to connect to the agent-only port." }, - "agentPortTls": { "type": "boolean", "default": true, "description": "Indicates if the agent-only port must perform TLS, this should be set to false if TLS is performed in front of this server." }, - "agentLogDump": { "type": "boolean", "default": false, "description": "Automatically downloads all agent error logs into meshcentral-data/agenterrorlogs.txt." }, - "agentCoreDump": { "type": "boolean", "default": false, "description": "Automatically activates and transfers any agent crash dump files to the server in meshcentral-data/coredumps." }, - "agentCoreDumpUsers": { "type": "array", "description": "List of non-administrator users that have access to mesh agent crash dumps." }, - "agentSignLock": { "type": "boolean", "default": false, "description": "When code signing an agent using authenticode, lock the agent to only allow connection to this server. (This is in testing, the default value will change to true in the future)." }, - "agentTimeStampServer": { "type": [ "boolean", "string" ], "default": "http://timestamp.comodoca.com/authenticode", "description": "The time stamping server to use when code signing Windows executables. When set to false, the executables are not time stamped." }, - "agentTimeStampProxy": { "type": [ "boolean", "string" ], "description": "The HTTP proxy to use when contacting the time stamping server, if false, no proxy is used. By default, the npmproxy value is used." }, - "ignoreAgentHashCheck": { "type": [ "boolean", "string" ], "default": false, "description": "When true, the agent no longer checked the TLS certificate of the server. This should be used for debugging only. You can also set this to a comma separated list of IP addresses to ignore, for example: \"192.168.2.100,192.168.1.0/24\"." }, - "exactPorts": { "type": "boolean", "default": false, "description": "When set to true, MeshCentral will only grab the required TCP listening ports or fail. It will not try to use the next available port of it's busy." }, - "allowLoginToken": { "type": "boolean", "default": false }, - "StrictTransportSecurity": { "type": ["boolean", "string"], "default": null, "description": "Controls the Strict-Transport-Security header, default is 1 year. Set to false to remove, true to force enable, or string to set a custom value. If set to null, MeshCentral will enable if a trusted certificate is set." }, - "allowFraming": { "type": "boolean", "default": false, "description": "When enabled, the MeshCentral web site can be embedded within another website's iframe." }, - "cookieIpCheck": { "type": [ "string", "boolean" ], "default": "lax", "enum": ["strict", "lax", "none"] }, - "cookieEncoding": { "type": "string", "enum": [ "hex", "base64" ], "default": "base64", "description": "Encoding format of cookies in the HTTP headers, this is typically Base64 but some reverse proxies will require HEX." }, - "webRTC": { "type": "boolean", "default": false, "description": "When enabled, allows use of WebRTC to allow direct network traffic between the agent and browser." }, - "nice404": { "type": "boolean", "default": true, "description": "By default, a nice looking 404 error page is displayed when needed. Set this to false to disable it." }, - "selfUpdate": { "type": "boolean", "default": false, "description": "When true, this server will attempt to self-update everyday after midnight." }, - "cleanNpmCacheOnUpdate": { "type": "boolean", "default": false, "description": "When true, run \"npm cache clean --force\" to reclaim disk space." }, - "browserPing": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the browser at x seconds interval and expects a response from the browser." }, - "browserPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the browser at x seconds interval." }, - "agentsInRam": { "type": "boolean", "default": false, "description": "Loads all agent binaries in RAM for faster agent updates." }, - "agentPing": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval and expects a response from the agent." }, - "agentPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval." }, - "amtManager": { "type": "boolean", "default": true, "description": "When enabled, MeshCentral will automatically monitor and manage Intel AMT devices." }, - "orphanAgentUser": { "type": "string", "default": null, "description": "If an agent attempts to connect to a unknown device group, automatically create a new device group and grant access to the specified user. Example: admin" }, - "agentIdleTimeout": { "type": "integer", "minimum": 1, "default": 150 ,"description": "How much time in seconds with no traffic from an agent before dropping the agent connection." }, - "webPageLengthRandomization": { "type": "boolean", "default": true, "description": "Adds a random length string to generated web pages to mitigate a BREACH attack." }, - "compression": { "type": "boolean", "default": true, "description": "Enables GZIP compression for web requests." }, - "wsCompression": { "type": "boolean", "default": false, "description": "Enables server-side, websocket per-message deflate compression." }, - "agentWsCompression": { "type": "boolean", "default": true, "description": "Enables agent-side, websocket per-message deflate compression. wscompression must also be true for this to work." }, - "noAgentUpdate": { "type": "integer", "default": 0, "description": "Set to 1 to present the server from updating any agent." }, - "agentUpdateSystem": { "type": "integer", "default": 1, "description": "When set to 2, all agents that need to be updated will use the meshcore.js update system. With the default value of 1, the native update system is used." }, - "temporaryAgentUpdate": { "type": "boolean", "default": true, "description": "Set to false to not allow temporary agents to be updated." }, - "amtScanner": { "type": "boolean", "default": true, "description": "Set to false to disable Intel AMT scanning on the local network, this is already disabled in WAN mode." }, - "meshScanner": { "type": "boolean", "default": true, "description": "Set to false to disable agent multicast scanning on the local network, this is already disabled in WAN mode." }, - "meshErrorLogPath": { "type": "string" }, - "npmPath": { "type": "string" }, - "npmProxy": { "type": "string", "format": "uri" }, - "allowHighQualityDesktop": { "type": "boolean", "default": true, "description": "When false, users will only be able to set remote desktop image quality to 60%, this can reduce server bandwidth usage." }, + "port": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "default": 443, + "description": "Ths port of the main HTTPS server." + }, + "portBind": { + "type": "string", + "description": "When set, bind the HTTPS main port to a specific network address." + }, + "aliasPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "default": null, + "description": "The actual main port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." + }, + "redirPort": { + "type": "integer", + "minimum": 0, + "maximum": 65535, + "default": 80, + "description": "This is a HTTP web server port that mostly redirects users to the HTTPS port but does provide some other services, 0 will turn this port off." + }, + "redirPortBind": { + "type": "string", + "description": "When set, bind the HTTP redirection port to a specific network address." + }, + "redirAliasPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "The actual redirection port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." + }, + "relayPort": { + "type": "integer", + "minimum": 0, + "maximum": 65535, + "default": 0, + "description": "When set, a web relay web server is bound to this port and will allow user access to remote web sites." + }, + "relayAliasPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "default": null, + "description": "The actual relay port as seen externally on the Internet, this setting is often used when a reverse-proxy is used." + }, + "relayDNS": { + "type": "string", + "default": null, + "description": "When set, relayPort value is ignored. Set this to a DNS name the points to this server. When the server is accessed using the DNS name, the main web server port is used as a web relay port." + }, + "agentPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "When set, enabled a new HTTPS server port that only accepts agent connections." + }, + "agentPortBind": { + "type": "string", + "description": "When set, binds the agent port to a specific network interface." + }, + "agentAliasPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "When set, indicates the actual publicly visible agent-only port. If not set, the AgentPort value is used." + }, + "agentAliasDNS": { + "type": "string", + "format": "hostname", + "description": "When set, specified the DNS name used by agents to connect to the agent-only port." + }, + "agentPortTls": { + "type": "boolean", + "default": true, + "description": "Indicates if the agent-only port must perform TLS, this should be set to false if TLS is performed in front of this server." + }, + "agentLogDump": { + "type": "boolean", + "default": false, + "description": "Automatically downloads all agent error logs into meshcentral-data/agenterrorlogs.txt." + }, + "agentCoreDump": { + "type": "boolean", + "default": false, + "description": "Automatically activates and transfers any agent crash dump files to the server in meshcentral-data/coredumps." + }, + "agentCoreDumpUsers": { + "type": "array", + "description": "List of non-administrator users that have access to mesh agent crash dumps." + }, + "agentSignLock": { + "type": "boolean", + "default": false, + "description": "When code signing an agent using authenticode, lock the agent to only allow connection to this server. (This is in testing, the default value will change to true in the future)." + }, + "agentTimeStampServer": { + "type": [ + "boolean", + "string" + ], + "default": "http://timestamp.comodoca.com/authenticode", + "description": "The time stamping server to use when code signing Windows executables. When set to false, the executables are not time stamped." + }, + "agentTimeStampProxy": { + "type": [ + "boolean", + "string" + ], + "description": "The HTTP proxy to use when contacting the time stamping server, if false, no proxy is used. By default, the npmproxy value is used." + }, + "lockAgentDownload": { + "type": "boolean", + "default": false, + "description": "When enabled, MeshCentral will block all downloads of MeshAgent including install scripts, if the user is not logged in" + }, + "ignoreAgentHashCheck": { + "type": [ + "boolean", + "string" + ], + "default": false, + "description": "When true, the agent no longer checked the TLS certificate of the server. This should be used for debugging only. You can also set this to a comma separated list of IP addresses to ignore, for example: \"192.168.2.100,192.168.1.0/24\"." + }, + "exactPorts": { + "type": "boolean", + "default": false, + "description": "When set to true, MeshCentral will only grab the required TCP listening ports or fail. It will not try to use the next available port of it's busy." + }, + "allowLoginToken": { + "type": "boolean", + "default": false, + "description": "When set to true, MeshCentral will allow login tokens to be used in the URL as a replacement for user login. This is useful along with \"allowFraming\" option to embed MeshCentral features into another website" + }, + "StrictTransportSecurity": { + "type": [ + "boolean", + "string" + ], + "default": null, + "description": "Controls the Strict-Transport-Security header, default is 1 year. Set to false to remove, true to force enable, or string to set a custom value. If set to null, MeshCentral will enable if a trusted certificate is set." + }, + "allowFraming": { + "type": "boolean", + "default": false, + "description": "When enabled, the MeshCentral web site can be embedded within another website's iframe." + }, + "cookieIpCheck": { + "type": [ + "string", + "boolean" + ], + "default": "lax", + "enum": [ + "strict", + "lax", + "none" + ] + }, + "cookieEncoding": { + "type": "string", + "enum": [ + "hex", + "base64" + ], + "default": "base64", + "description": "Encoding format of cookies in the HTTP headers, this is typically Base64 but some reverse proxies will require HEX." + }, + "webRTC": { + "type": "boolean", + "default": false, + "description": "When enabled, allows use of WebRTC to allow direct network traffic between the agent and browser." + }, + "nice404": { + "type": "boolean", + "default": true, + "description": "By default, a nice looking 404 error page is displayed when needed. Set this to false to disable it." + }, + "selfUpdate": { + "type": [ + "string", + "boolean" + ], + "default": false, + "description": "When set to true, the server will check for a new version and attempt to self-update automatically a bit after midnight local time every day. If set to a specific version such as \"1.1.21\" the server will immediately update to the specified version on startup if it's not already at this version." + }, + "cleanNpmCacheOnUpdate": { + "type": "boolean", + "default": false, + "description": "When true, run \"npm cache clean --force\" to reclaim disk space." + }, + "browserPing": { + "type": "integer", + "minimum": 1, + "description": "When specified, sends data to the browser at x seconds interval and expects a response from the browser." + }, + "browserPong": { + "type": "integer", + "minimum": 1, + "description": "When specified, sends data to the browser at x seconds interval." + }, + "agentsInRam": { + "type": "boolean", + "default": false, + "description": "Loads all agent binaries in RAM for faster agent updates." + }, + "agentPing": { + "type": "integer", + "minimum": 1, + "description": "When specified, sends data to the agent at x seconds interval and expects a response from the agent." + }, + "agentPong": { + "type": "integer", + "minimum": 1, + "description": "When specified, sends data to the agent at x seconds interval." + }, + "amtManager": { + "type": "boolean", + "default": true, + "description": "When enabled, MeshCentral will automatically monitor and manage Intel AMT devices." + }, + "agentIdleTimeout": { + "type": "integer", + "minimum": 1, + "default": 150, + "description": "How much time in seconds with no traffic from an agent before dropping the agent connection." + }, + "webPageLengthRandomization": { + "type": "boolean", + "default": true, + "description": "Adds a random length string to generated web pages to mitigate a BREACH attack." + }, + "compression": { + "type": "boolean", + "default": true, + "description": "Enables GZIP compression for web requests." + }, + "wsCompression": { + "type": "boolean", + "default": false, + "description": "Enables server-side, websocket per-message deflate compression." + }, + "agentWsCompression": { + "type": "boolean", + "default": true, + "description": "Enables agent-side, websocket per-message deflate compression. wscompression must also be true for this to work." + }, + "noAgentUpdate": { + "type": "integer", + "default": 0, + "description": "Set to 1 to present the server from updating any agent." + }, + "agentUpdateSystem": { + "type": "integer", + "default": 1, + "description": "When set to 2, all agents that need to be updated will use the meshcore.js update system. With the default value of 1, the native update system is used." + }, + "temporaryAgentUpdate": { + "type": "boolean", + "default": true, + "description": "Set to false to not allow temporary agents to be updated." + }, + "amtScanner": { + "type": "boolean", + "default": true, + "description": "Set to false to disable Intel AMT scanning on the local network, this is already disabled in WAN mode." + }, + "meshScanner": { + "type": "boolean", + "default": true, + "description": "Set to false to disable agent multicast scanning on the local network, this is already disabled in WAN mode." + }, + "meshErrorLogPath": { + "type": "string" + }, + "npmPath": { + "type": "string" + }, + "npmProxy": { + "type": "string", + "format": "uri" + }, + "allowHighQualityDesktop": { + "type": "boolean", + "default": true, + "description": "When false, users will only be able to set remote desktop image quality to 60%, this can reduce server bandwidth usage." + }, "webPush": { "type": "object", "description": "When set with a valid email address, enables the MeshCentral web push notification feature. Allows administrators to send browser notifications to users even if they are not looking at the MeshCentral web site.", - "additionalProperties": false, "properties": { - "email": { "type": "string", "description": "Server administrator email given to the FireFox and Chrome push notification services." } + "email": { + "type": "string", + "description": "Server administrator email given to the FireFox and Chrome push notification services." + } }, - "required": [ "email" ] + "required": [ + "email" + ] + }, + "RunOnServerStarted": { + "type": "boolean", + "default": null, + "description": "Execute this when the server startup is completed. The first parameter will be the server version." + }, + "RunOnServerUpdated": { + "type": "boolean", + "default": null, + "description": "Execute this when the server has been updated. The first parameter will be the server version." + }, + "RunOnServerError": { + "type": "boolean", + "default": null, + "description": "Execute this when the server has to restart due to an error. The first parameter will be the server version." + }, + "publicPushNotifications": { + "type": "boolean", + "default": false, + "description": "When true, this server uses MeshCentral.com a push notification relay for Android notifications. Push notifications work even if the Android app is not open." + }, + "desktopMultiplex": { + "type": "boolean", + "default": false, + "description": "When true, enabled a server modules that efficiently splits a remote desktop stream to multiple browsers. Also allows slow browsers to not slow down the session for fast ones, this comes at the cost of extra server memory and processing for all remote desktop sessions." + }, + "ipBlockedUserRedirect": { + "type": "string", + "default": null, + "description": "If set, a user from a banned IP address will be redirected to this URL." + }, + "userAllowedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:userAllowedIP.txt\"" + }, + "userBlockedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:userBlockedIP.txt\"" + }, + "agentAllowedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:agentAllowedIP.txt\"" + }, + "agentBlockedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, agents from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:agentBlockedIP.txt\"" + }, + "authLog": { + "type": "string", + "default": null, + "description": "File path and name of the authentication log to be created. This log can be parsed by Fail2ban." + }, + "InterUserMessaging": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "description": "Users in this list are allowed to send and receive inter-user messages. This can be used to implement bots or other software where MeshCentral is used as data transport. See \"interuser\" websocket command in the code." + }, + "manageAllDeviceGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "description": "Users in this list are allowed to see and manage all device groups within their domain." + }, + "manageCrossDomain": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "description": "Users in this list are allowed to manage all users in all domains." }, - "RunOnServerStarted": { "type": "boolean", "default": null, "description": "Execute this when the server startup is completed. The first parameter will be the server version." }, - "RunOnServerUpdated": { "type": "boolean", "default": null, "description": "Execute this when the server has been updated. The first parameter will be the server version." }, - "RunOnServerError": { "type": "boolean", "default": null, "description": "Execute this when the server has to restart due to an error. The first parameter will be the server version." }, - "publicPushNotifications": { "type": "boolean", "default": false, "description": "When true, this server uses MeshCentral.com a push notification relay for Android notifications. Push notifications work even if the Android app is not open." }, - "desktopMultiplex": { "type": "boolean", "default": false, "description": "When true, enabled a server modules that efficiently splits a remote desktop stream to multiple browsers. Also allows slow browsers to not slow down the session for fast ones, this comes at the cost of extra server memory and processing for all remote desktop sessions." }, - "ipBlockedUserRedirect" : { "type": "string", "default": null, "description": "If set, a user from a banned IP address will be redirected to this URL." }, - "userAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "userBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, agents from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "authLog": { "type": "string", "default": null, "description": "File path and name of the authentication log to be created. This log can be parsed by Fail2ban." }, - "InterUserMessaging": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "description": "Users in this list are allowed to send and receive inter-user messages. This can be used to implement bots or other software where MeshCentral is used as data transport. See \"interuser\" websocket command in the code." }, - "manageAllDeviceGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "description": "Users in this list are allowed to see and manage all device groups within their domain." }, - "manageCrossDomain": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "description": "Users in this list are allowed to manage all users in all domains." }, "localDiscovery": { "type": "object", "description": "When this server is in LAN mode, you may discover this server using a multicast discovery tool. When discovery happens, the name and info fields are sent back to the discovery tool.", - "additionalProperties": false, "properties": { - "name": { "type": "string" }, - "info": { "type": "string" }, - "key": { "type": "string", "description": "When set, encrypts all LAN discovery traffic to agents and tools using this key. This is only useful in LAN/Hybrid mode when agents and tools user multicast to find the server." } + "name": { + "type": "string" + }, + "info": { + "type": "string" + }, + "key": { + "type": "string", + "description": "When set, encrypts all LAN discovery traffic to agents and tools using this key. This is only useful in LAN/Hybrid mode when agents and tools user multicast to find the server." + } }, - "required": [ "name", "info" ] + "required": [ + "name", + "info" + ] + }, + "tlsOffload": { + "type": [ + "boolean", + "string" + ], + "default": false, + "description": "When true, indicates that a TLS offloader is in front of the MeshCentral server. More typically, set this to the IP address of the reverse proxy or TLS offloader so that IP forwarding headers will be trusted. For example: \"127.0.0.1,192.168.1.100\"." + }, + "useNodeDefaultTLSCiphers": { + "type": "boolean", + "default": false, + "description": "When true, get the default TLS ciphers from the node process, rather than using the recommended suites set up by meshcentral" + }, + "tlsCiphers": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "Allows user to override the TLS ciphers used by meshcentral by default. If a string, should be a ':' separated list of ciphers to accept. If an array, should be an array of strings representing the ciphers to accept." + }, + "trustedProxy": { + "type": "string", + "default": null, + "description": "Trust forwarded headers from these IPs or domains. Providing the magic string \"CloudFlare\" will cause the server to download the IP address list of trusted CloudFlare proxies directly from CloudFlare on each server start. For example: \"127.0.0.1,proxy.example.com,CloudFlare\"." + }, + "mpsPort": { + "type": "integer", + "minimum": 0, + "maximum": 65535, + "default": 4433, + "description": "The Management Presence Server (MPS), this is the server that received Intel AMT Client Initiated Remote Access (CIRA) connections." + }, + "mpsPortBind": { + "type": "string", + "default": null + }, + "mpsAliasPort": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "default": null + }, + "mpsAliasHost": { + "type": "string", + "default": null + }, + "mpsTlsOffload": { + "type": "boolean", + "default": false, + "description": "When set to true, indicate that TLS is being performed by a device in front of MeshCentral." + }, + "mpsHighSecurity": { + "type": "boolean", + "default": false, + "description": "When set to true, the MPS server will only accept TLS 1.2 and 1.3 connections. Older Intel AMT devices will not be able to connect." + }, + "prometheus": { + "type": [ + "boolean", + "number" + ], + "default": false, + "description": "When set to true, a prometheus metrics endpoint will be available \"0.0.0.0:9464/metrics\". If you specify a number instead, the prometheus metrics will listen on this port instead of the default 9464." + }, + "no2FactorAuth": { + "type": "boolean", + "default": false + }, + "debug": { + "type": "string", + "default": null, + "description": "You can set this value in the format 'web,agent,relay', where each value is separated by a comma. Each specified value will output logs to the MeshCentral console. Setting it to '*' will output all logs." + }, + "log": { + "type": "string", + "default": null, + "description": "You can set this value in the format 'web,agent,relay', where each value is separated by a comma. Each specified value will output logs to a file named 'log.txt' located inside the 'meshcentral-data' folder. Setting it to '*' will output all logs." + }, + "syslog": { + "type": "string", + "default": null + }, + "syslogauth": { + "type": "string", + "default": null + }, + "syslogjson": { + "type": "string", + "default": null + }, + "syslogtcp": { + "type": "string", + "default": null, + "description": "Send syslog events over the network (RFC3164) to a target hostname:port. For example: localhost:514" }, - "tlsOffload": { "type": [ "boolean", "string" ], "default": false, "description": "When true, indicates that a TLS offloader is in front of the MeshCentral server. More typically, set this to the IP address of the reverse proxy or TLS offloader so that IP forwarding headers will be trusted. For example: \"127.0.0.1,192.168.1.100\"." }, - "trustedProxy": { "type": "string", "default": null, "description": "Trust forwarded headers from these IPs or domains. Providing the magic string \"CloudFlare\" will cause the server to download the IP address list of trusted CloudFlare proxies directly from CloudFlare on each server start. For example: \"127.0.0.1,proxy.example.com,CloudFlare\"." }, - "mpsPort": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 4433, "description": "The Management Presence Server (MPS), this is the server that received Intel AMT Client Initiated Remote Access (CIRA) connections." }, - "mpsPortBind": { "type": "string", "default": null }, - "mpsAliasPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": null }, - "mpsAliasHost": { "type": "string", "default": null }, - "mpsTlsOffload": { "type": "boolean", "default": false, "description": "When set to true, indicate that TLS is being performed by a device in front of MeshCentral." }, - "mpsHighSecurity": { "type": "boolean", "default": false, "description": "When set to true, the MPS server will only accept TLS 1.2 and 1.3 connections. Older Intel AMT devices will not be able to connect." }, - "no2FactorAuth": { "type": "boolean", "default": false }, - "log": { "type": "string", "default": null }, - "syslog": { "type": "string", "default": null }, - "syslogauth": { "type": "string", "default": null }, - "syslogjson": { "type": "string", "default": null }, - "syslogtcp": { "type": "string", "default": null, "description": "Send syslog events over the network (RFC3164) to a target hostname:port. For example: localhost:514" }, "webrtcConfig": { "type": "object", - "additionalProperties": false, - "description": "The STUN servers used for WebRTC, if not specified the Google and Mozilla servers and used when the server is not in LAN mode.", + "description": "The STUN/TURN servers used for WebRTC, if not specified the Google and Cloudflare STUN servers are used when the server is not in LAN mode.", "properties": { - "iceServers": { "type": "array", "uniqueItems": true, "items": { "type": "object", "additionalProperties": false, "properties": { "urls": { "type": "string" } }, "required": [ "urls" ] } } + "iceServers": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "properties": { + "urls": { + "type": "string", + "description": "STUN/TURN URLs, examples are stun:stun3.l.google.com:19302 or turn:openrelay.metered.ca:443" + } + }, + "required": [ + "urls" + ] + } + } }, - "required": [ "iceServers" ] + "required": [ + "iceServers" + ] }, "crowdsec": { "type": "object", - "additionalProperties": true, "description": "Enabled the MeshCentral built-in Crowdsec bouncer. This section is passed directly to the bouncer, all of the settings are documented at https://www.npmjs.com/package/@crowdsec/express-bouncer", "properties": { - "url": { "type": "string", "description": "The URL of your LAPI instance. Ex: http://localhost:8080" }, - "apiKey": { "type": "string", "description": "The bouncer key (generated via cscli)." }, - "fallbackRemediation": { "type": "string", "default": "ban", "enum": ["bypass", "captcha", "ban"], "description": "Action to perform if the CrowdSec agent can't be contacted." } + "url": { + "type": "string", + "description": "The URL of your LAPI instance. Ex: http://localhost:8080" + }, + "apiKey": { + "type": "string", + "description": "The bouncer key (generated via cscli)." + }, + "fallbackRemediation": { + "type": "string", + "default": "ban", + "enum": [ + "bypass", + "captcha", + "ban" + ], + "description": "Action to perform if the CrowdSec agent can't be contacted." + } }, - "required": [ "url", "apiKey" ] + "required": [ + "url", + "apiKey" + ] }, "autoBackup": { - "type": "object", + "type": [ + "boolean", + "object" + ], + "description": "Enabled by default or if set to true. Disabled if set to false. An object can be provided with additional properties to set autobackup options.", "properties": { - "mongoDumpPath": { "type": "string" }, - "mysqlDumpPath": { "type": "string" }, - "backupIntervalHours": { "type": "integer" }, - "keepLastDaysBackup": { "type": "integer" }, - "zipPassword": { "type": "string" }, - "backupPath": { "type": "string" }, + "mongoDumpPath": { + "type": "string", + "default": "mongodump", + "description": "The file path of where \"mongodump\" is located. Default is \"mongodump\"" + }, + "mysqlDumpPath": { + "type": "string", + "default": "mysqldump", + "description": "The file path of where \"mysqldump\" is located. Default is \"mysqldump\"" + }, + "pgDumpPath": { + "type": "string", + "default": "pg_dump", + "description": "The file path of where \"pg_dump\" is located. Default is \"pg_dump\"" + }, + "backupIntervalHours": { + "type": "integer", + "default": 24, + "description": "How often should the autobackup run in hours from the second meshcentral starts up? Default is every 24 hours" + }, + "backupHour": { + "type": "integer", + "default": 0, + "description": "At which hour the autobackup should run. This forces a daily backup, overrules a custom 'backupIntervalHours'." + }, + "keepLastDaysBackup": { + "type": "integer", + "default": 10, + "description": "How many days of backups should the autobackup keep? Default is 10 Days worth" + }, + "zipCompression" : { + "type": "integer", + "default": "5", + "description": "Set the zip compression level, 1=fast/less small file to 9=slow/smallest file." + }, + "zipPassword": { + "type": "string", + "default": "", + "minLength": 1, + "description": "When specified, the ZIP backups will be password protected with the zipPassword and the password cannot be a blank value" + }, + "backupPath": { + "type": "string", + "default": "meshcentral-backups", + "description": "The file path where backup files are kept. The default is \"meshcentral-backups\" which sits next to \"meshcentral-data\"." + }, + "backupName": { + "type": "string", + "default": "meshcentral-autobackup-", + "description": "The filename of the backupfile. The default is \"meshcentral-autobackup-\", the filename is appended with the time of backup." + }, + "backupWebFolders": { + "type": "boolean", + "default": false, + "description": "Add views, public and emails directories if overridden" + }, + "backupOtherFolders": { + "type": "boolean", + "default": false, + "description": "Also add files and recordings folder to the backup" + }, + "backupIgnoreFilesGlob": { + "type": "array", + "default": [], + "description": "Glob for ignoring files in the data directory. For example [\"**/*.log\"] !! If a string instead of an array is passed, it will be split by ',' so *{.txt,.log} won't work in that case !! Don't do string..." + }, + "backupSkipFoldersGlob":{ + "type": "array", + "default": [], + "description": "Glob for ignoring directories in the data directory. For example [\"**/signedagents\"]" + }, "googleDrive": { "type": "object", "description": "Enabled automated upload of the server backups to a Google Drive account, once enabled you need to go in \"My Server\" tab as administrator to associate the account.", @@ -265,37 +980,125 @@ "description": "The maximum number of files to keep in the WebDAV folder, older files will be removed if needed." } } + }, + "s3": { + "type": "object", + "description": "Enabled automated upload of the server backups to an S3 server.", + "required": [ + "accessKey", + "secretKey", + "bucketName" + ], + "properties": { + "endpoint": { + "type": "string", + "default": "s3.amazonaws.com", + "description": "S3 Endpoint address e.g. myS3.myserver.com" + }, + "accessKey": { + "type": "string", + "description": "S3 accessKey, Required" + }, + "secretKey": { + "type": "string", + "description": "S3 secretKey, Required" + }, + "port": { + "type": "integer", + "default": 443, + "description": "S3 Endpoint port number, Default is 443" + }, + "ssl": { + "type": "boolean", + "default": true, + "description": "If \"true\", the S3 Endpoint will use \"https\", else it will use \"http\", Default is true" + }, + "bucketName": { + "type": "string", + "description": "S3 Bucket Name, Required" + }, + "folderName": { + "type": "string", + "default": "MeshCentral-Backups", + "description": "The name of the folder to create in the S3 Bucket. Defaults to \"MeshCentral-Backups\"." + }, + "maxFiles": { + "type": "integer", + "default": 0, + "description": "The maximum number of files to keep in the S3 folder, older files will be removed if needed. Default is 0 which is keep everything." + } + } } } }, - "rootCertCommonName" : { "type": "string", "default": "MeshCentralRoot-XXXXXX", "description": "The common name of the MeshCentral server root certificate. By default it's 'MeshCentralRoot-' followed by the first 6 HEX digits of the public key fingerprint. For this setting to take effect, all generated certificates need to be deleted and reset. Existing agents will not be able to connect anymore." }, - "redirects": { "type": "object" }, + "rootCertCommonName": { + "type": "string", + "default": "MeshCentralRoot-XXXXXX", + "description": "The common name of the MeshCentral server root certificate. By default it's 'MeshCentralRoot-' followed by the first 6 HEX digits of the public key fingerprint. For this setting to take effect, all generated certificates need to be deleted and reset. Existing agents will not be able to connect anymore." + }, + "redirects": { + "type": "object" + }, "maxInvalidLogin": { "type": "object", - "additionalProperties": false, "description": "This section described a policy for how many times an IP address is allowed to attempt to login incorrectly. By default it's 10 times in 10 minutes, but this can be changed here.", "properties": { - "exclude": { "type": "string", "default": null, "description": "Ranges of IP addresses that are not subject to invalid login limitations. For example: 192.168.1.0/24,172.16.0.1"}, - "time": { "type": "integer", "default": 10, "description": "Time in minutes over which the a maximum number of invalid login attempts is allowed from an IP address." }, - "count": { "type": "integer", "default": 10, "description": "Maximum number of invalid login attempts from an IP address in the time period." }, - "coolofftime": { "type": "integer", "default": null, "description": "Additional time in minute that login attempts will be denied once the invalid login limit is reached." } + "exclude": { + "type": "string", + "default": null, + "description": "Ranges of IP addresses that are not subject to invalid login limitations. For example: 192.168.1.0/24,172.16.0.1" + }, + "time": { + "type": "integer", + "default": 10, + "description": "Time in minutes over which the a maximum number of invalid login attempts is allowed from an IP address." + }, + "count": { + "type": "integer", + "default": 10, + "description": "Maximum number of invalid login attempts from an IP address in the time period." + }, + "coolofftime": { + "type": "integer", + "default": null, + "description": "Additional time in minute that login attempts will be denied once the invalid login limit is reached." + } } }, "maxInvalid2fa": { "type": "object", - "additionalProperties": false, "description": "This section described a policy for how many times an IP address is allowed to attempt to perform two-factor authentication (2FA) incorrectly. By default it's 10 times in 10 minutes, but this can be changed here.", "properties": { - "exclude": { "type": "string", "default": null, "description": "Ranges of IP addresses that are not subject to invalid 2FA limitations. For example: 192.168.1.0/24,172.16.0.1"}, - "time": { "type": "integer", "default": 10, "description": "Time in minutes over which the a maximum number of invalid 2FA attempts is allowed from an IP address." }, - "count": { "type": "integer", "default": 10, "description": "Maximum number of invalid 2FA attempts from an IP address in the time period." }, - "coolofftime": { "type": "integer", "default": null, "description": "Additional time in minute that 2FA attempts will be denied once the invalid 2FA limit is reached." } + "exclude": { + "type": "string", + "default": null, + "description": "Ranges of IP addresses that are not subject to invalid 2FA limitations. For example: 192.168.1.0/24,172.16.0.1" + }, + "time": { + "type": "integer", + "default": 10, + "description": "Time in minutes over which the a maximum number of invalid 2FA attempts is allowed from an IP address." + }, + "count": { + "type": "integer", + "default": 10, + "description": "Maximum number of invalid 2FA attempts from an IP address in the time period." + }, + "coolofftime": { + "type": "integer", + "default": null, + "description": "Additional time in minute that 2FA attempts will be denied once the invalid 2FA limit is reached." + } } }, "amtProvisioningServer": { "type": "object", - "additionalProperties": false, - "required": [ "deviceGroup", "newMebxPassword", "trustedFqdn", "ip" ], + "required": [ + "deviceGroup", + "newMebxPassword", + "trustedFqdn", + "ip" + ], "description": "When present, this section will enable the Intel AMT provisioning server on the local network. This is used for Intel AMT bare-metal ACM activation.", "properties": { "port": { @@ -323,66 +1126,299 @@ }, "plugins": { "type": "object", - "properties": { "enabled": { "type": "boolean" } }, - "required": [ "enabled" ] + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + }, + "watchdog": { + "type": "object", + "required": [ + "interval", + "timeout" + ], + "description": "This is used to monitor if NodeJS is servicing IO correctly or getting held up a lot. You MUST specify \"interval\" and \"timeout\".", + "properties": { + "interval": { + "type": "number", + "description": " This will check every X ms" + }, + "timeout": { + "type": "number", + "description": " If the timer is more than X ms late, it will warn to console AND mesherrors.txt" + } + } } } }, - "domaindefaults": { "$ref": "#/properties/domains/items" }, + "domaindefaults": { + "$ref": "#/properties/domains/additionalProperties" + }, "domains": { "type": "object", - "items": { + "additionalProperties": { "type": "object", "properties": { - "siteStyle": { "type": "integer", "default": 2, "description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages." }, - "title": { "type": "string", "default": "MeshCentral", "description": "The title of this web site. All web pages will have this title." }, - "title2": { "type": "string", "default": null, "description": "Secondary title text that is placed on the upper right on the title on many web pages." }, - "titlePicture": { "type": "string", "default": null, "description": "Web site .png logo file that is 450x66 in size placed in meshcentral-data that is used on the top of many pages." }, - "loginPicture": { "type": "string", "default": null, "description": "Web site .png logo file placed in meshcentral-data that used on the login page when sitestyle is 2." }, - "rootRedirect": { "type": "string", "default": null, "description": "Redirects HTTP root requests to this URL. When in use, direct users to /login to see the normal login page." }, - "mobileSite": { "type": "boolean", "default": true, "description": "When set to false, this setting will disable the mobile site." }, - "maxDeviceView": { "type": "integer", "default": null, "description": "The maximum number of devices a user can see on the devices page at the same time. By default all devices will show, but this may need to be limited on servers with large number of devices." }, - "unknownUserRootRedirect": { "type": "string", "default": null, "description": "Redirects HTTP root requests to this URL only where user is not already logged in. When in use, direct users to /login to see the normal login page." }, - "nightMode": { "type": "integer", "default": 0, "description": "0 = User selects day/night mode, 1 = Always night mode, 2 = Always day mode" }, - "userQuota": { "type": "integer" }, - "meshQuota": { "type": "integer" }, - "loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." }, - "agentKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." }, - "ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." }, - "minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sized web pages." }, - "newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." }, - "newAccountsPass": { "type": "string", "default": null, "description": "When set this password will be required in order to create a new account from the login screen." }, - "newAccountsCaptcha": { "type": "boolean", "default": false, "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "userNameIsEmail": { "type": "boolean", "default": false, "description": "When enabled, the username of each account is also the email address of the account." }, - "newAccountEmailDomains": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "newAccountsRights": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "welcomeText": { "type": "string", "description": "Text that will be shown on the login screen." }, - "welcomePicture": { "type": "string", "description": "Name of the PNG or JPEG file that will be shown on the login screen. Put this file in the meshcentral-data folder and place the file name here." }, - "welcomePictureFullScreen": { "type": "boolean", "default": false, "description": "When enabled, the welcomePicture will show as a fullscreen background on the login screen." }, - "meshMessengerTitle": { "type": "string", "default": "MeshMessenger", "description": "Text that will be displayed on the top of the messenger window when no username or device name is displayed." }, - "meshMessengerPicture": { "type": "string", "default": null, "description": "Name of a .png image file that is placed in meshcentral-data that is displayed on the top of the messenger web page. When null, the default image is displayed." }, - "hide": { "type": "integer", "default": 0, "description": "Sum of: 1 = Hide header, 2 = Hide tab, 4 = Hide footer, 8 = Hide title, 16 = Hide left bar, 32 = Hide back buttons" }, - "footer": { "type": "string", "default": null, "description": "This is a HTML string displayed at the bottom of the web page when a user is logged in." }, - "loginfooter": { "type": "string", "default": null, "description": "This is a HTML string displayed at the bottom of the web page when a user is not logged in." }, - "allowSavingDeviceCredentials": { "type": "boolean", "default": true, "description": "Allow users to save SSH, RDP, VNC device credentials on the server that can be used by any other user." }, - "trustedCert": { "type": "boolean", "default": "This value is normally auto-detected, when set to true, MeshCentral assumes that the TLS certificate comes from a trusted CA and will insure download tools perform certificate checking." }, + "dns": { + "type": "string", + "default": null, + "description": "The DNS name used to access this domain instead of accessing it via a subfolder" + }, + "siteStyle": { + "type": "integer", + "default": 2, + "description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages." + }, + "showModernUIToggle": { + "type": "boolean", + "default": false, + "description": "When set to true, the user will be able to toggle between the modern and classic UI." + }, + "title": { + "type": "string", + "default": "MeshCentral", + "description": "The title of this web site. All web pages will have this title." + }, + "title2": { + "type": "string", + "default": null, + "description": "Secondary title text that is placed on the upper right on the title on many web pages." + }, + "titlePicture": { + "type": "string", + "default": null, + "description": "Web site .png logo file that is 450x66 in size placed in meshcentral-data that is used on the top of many pages." + }, + "loginPicture": { + "type": "string", + "default": null, + "description": "Web site .png logo file placed in meshcentral-data that used on the login page when sitestyle is 2." + }, + "pwaLogo": { + "type": "string", + "default": null, + "description": "Web site .png logo file that is 512x512 in size placed in meshcentral-data that is used for PWA installs on iOS and Android." + }, + "rootRedirect": { + "type": "string", + "default": null, + "description": "Redirects HTTP root requests to this URL. When in use, direct users to /login to see the normal login page." + }, + "mobileSite": { + "type": "boolean", + "default": true, + "description": "When set to false, this setting will disable the mobile site." + }, + "orphanAgentUser": { + "type": "string", + "default": null, + "description": "If an agent attempts to connect to a unknown device group, automatically create a new device group and grant access to the specified user. Example: admin" + }, + "maxDeviceView": { + "type": "integer", + "default": null, + "description": "The maximum number of devices a user can see on the devices page at the same time. By default all devices will show, but this may need to be limited on servers with large number of devices." + }, + "unknownUserRootRedirect": { + "type": "string", + "default": null, + "description": "Redirects HTTP root requests to this URL only where user is not already logged in. When in use, direct users to /login to see the normal login page." + }, + "nightMode": { + "type": "integer", + "default": 0, + "description": "0 = User selects day/night mode, 1 = Always night mode, 2 = Always day mode" + }, + "scrollToTop": { + "type": "boolean", + "default": false, + "description": "If true, a Scroll To Top button in the devices tab." + }, + "userQuota": { + "type": "integer" + }, + "meshQuota": { + "type": "integer" + }, + "loginKey": { + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + }, + "default": null, + "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." + }, + "agentKey": { + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + }, + "default": null, + "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." + }, + "ipkvm": { + "type": "boolean", + "default": false, + "description": "Set to true to enable IP KVM device support in this domain." + }, + "minify": { + "type": "boolean", + "default": false, + "description": "When enabled, the server will send reduced sized web pages." + }, + "newAccounts": { + "type": "boolean", + "default": false, + "description": "When set to true, allow new user accounts to be created from the login page." + }, + "newAccountsPass": { + "type": "string", + "default": null, + "description": "When set this password will be required in order to create a new account from the login screen." + }, + "newAccountsCaptcha": { + "type": "boolean", + "default": false, + "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "userNameIsEmail": { + "type": "boolean", + "default": false, + "description": "When enabled, the username of each account is also the email address of the account." + }, + "newAccountEmailDomains": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "newAccountsRights": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "allowedOrigin": { + "type": [ + "array", + "boolean" + ], + "default": false, + "uniqueItems": true, + "description": "A list of allowed hostnames for HTTP request origin header. If false, a default list is created, if true, all hostnames are allowed.", + "items": { + "type": "string" + } + }, + "welcomeText": { + "type": "string", + "description": "Text that will be shown on the login screen." + }, + "welcomePicture": { + "type": "string", + "description": "Name of the PNG or JPEG file that will be shown on the login screen. Put this file in the meshcentral-data folder and place the file name here." + }, + "welcomePictureFullScreen": { + "type": "boolean", + "default": false, + "description": "When enabled, the welcomePicture will show as a fullscreen background on the login screen." + }, + "meshMessengerTitle": { + "type": "string", + "default": "MeshMessenger", + "description": "Text that will be displayed on the top of the messenger window when no username or device name is displayed." + }, + "meshMessengerPicture": { + "type": "string", + "default": null, + "description": "Name of a .png image file that is placed in meshcentral-data that is displayed on the top of the messenger web page. When null, the default image is displayed." + }, + "hide": { + "type": "integer", + "default": 0, + "description": "Sum of: 1 = Hide header, 2 = Hide tab, 4 = Hide footer, 8 = Hide title, 16 = Hide left bar, 32 = Hide back buttons" + }, + "footer": { + "type": "string", + "default": null, + "description": "This is a HTML string displayed at the bottom of the web page when a user is logged in." + }, + "loginfooter": { + "type": "string", + "default": null, + "description": "This is a HTML string displayed at the bottom of the web page when a user is not logged in." + }, + "allowSavingDeviceCredentials": { + "type": "boolean", + "default": true, + "description": "Allow users to save SSH, RDP, VNC device credentials in the server." + }, + "trustedCert": { + "type": "boolean", + "default": "This value is normally auto-detected, when set to true, MeshCentral assumes that the TLS certificate comes from a trusted CA and will ensure download tools perform certificate checking." + }, "guestDeviceSharing": { - "type": [ "boolean", "object" ], + "type": [ + "boolean", + "object" + ], "default": true, "description": "When set to false, the desktop/terminal sharing link feature is not available.", "properties": { - "maxSessionTime": { "type": "number", "description": "When set, limits the maximum length of a guest session, in minutes." } + "maxSessionTime": { + "type": "number", + "description": "When set, limits the maximum length of a guest session, in minutes." + } } }, - "autoRemoveInactiveDevices": { "type": "integer", "default": 0, "minimum": 0, "maximum": 2000, "description": "Number of days a device can be inactive before it's removed. 0 disables this feature. Device group setting will override this value." }, - "deviceSearchBarServerAndClientName": { "type": "boolean", "default": false, "description": "When set to true, the devices search box will match on both the server name and client name of a device." }, + "autoRemoveInactiveDevices": { + "type": "integer", + "default": 0, + "minimum": 0, + "maximum": 2000, + "description": "Number of days a device can be inactive before it's removed. 0 disables this feature. Device group setting will override this value." + }, + "deviceSearchBarServerAndClientName": { + "type": "boolean", + "default": false, + "description": "When set to true, the devices search box will match on both the server name and client name of a device." + }, + "deviceSearchBarGroupName": { + "type": "boolean", + "default": false, + "description": "When set to true, the devices search box will match on group name too." + }, "agentSelfGuestSharing": { - "type": [ "boolean", "object" ], + "type": [ + "boolean", + "object" + ], "default": false, "description": "When set to true, MeshCentral Assistant can create it's own guest sharing links.", "properties": { - "expire": { "type": "number", "description": "When set, limits the self-created guest sharing link to this number of minutes." } + "expire": { + "type": "number", + "description": "When set, limits the self-created guest sharing link to this number of minutes." + } } }, "PreconfiguredScripts": { @@ -391,7 +1427,10 @@ "description": "When set, your can try click the run button to run on of these scripts on the remote device.", "items": { "type": "object", - "required": [ "name", "type" ], + "required": [ + "name", + "type" + ], "properties": { "name": { "description": "Name of the script.", @@ -400,12 +1439,21 @@ "type": { "description": "The type of script.", "type": "string", - "enum": [ "bat", "ps1", "sh", "agent" ] + "enum": [ + "bat", + "ps1", + "sh", + "agent" + ] }, "runas": { "description": "How to run this script, does not apply to agent scripts.", "type": "string", - "enum": ["agent", "userfirst", "user"] + "enum": [ + "agent", + "userfirst", + "user" + ] }, "cmd": { "description": "The command or \\r\\n separated commands to run, if set do not use the file key.", @@ -424,7 +1472,10 @@ "description": "When set, you can right click on the input button in the desktop tab and instantly remotely type one of these pre-configured strings.", "items": { "type": "object", - "required": [ "name", "value" ], + "required": [ + "name", + "value" + ], "properties": { "name": { "description": "Name of the text string.", @@ -442,288 +1493,827 @@ "items": { "type": "object", "properties": { - "name": { "type": "string", "description": "Name of the alternative messaging service, for example: \"Jitsi\" " }, - "url": { "type": "string", "description": "URL to the alternative messaging services, for example: \"https://meet.jit.si/myserver-{0}\", for a device {0}, {1}, {2}, {3} is the device id. For a user, {0} is the userid, {1} is full userid with dashes, {2} is real name with no spaces, {3} is real name with dash instead of spaces." }, - "localurl": { "type": "string", "description": "If specified, this is the URL that is used on the administrator side, for example: \"https://meet.jit.si/myserver-{0}\", for a device {0}, {1}, {2}, {3} is the device id. For a user, {0} is the userid, {1} is full userid with dashes, {2} is real name with no spaces, {3} is real name with dash instead of spaces." }, - "type": { "type": "string", "enum": [null, "user", "device"], "default": null, "description": "Indicate if this button should be shown in the user or device type. If omitted, it will be displayed in both." } + "name": { + "type": "string", + "description": "Name of the alternative messaging service, for example: \"Jitsi\" " + }, + "url": { + "type": "string", + "description": "URL to the alternative messaging services, for example: \"https://meet.jit.si/myserver-{0}\", for a device {0}, {1}, {2}, {3} is the device id. For a user, {0} is the userid, {1} is full userid with dashes, {2} is real name with no spaces, {3} is real name with dash instead of spaces." + }, + "localurl": { + "type": "string", + "description": "If specified, this is the URL that is used on the administrator side, for example: \"https://meet.jit.si/myserver-{0}\", for a device {0}, {1}, {2}, {3} is the device id. For a user, {0} is the userid, {1} is full userid with dashes, {2} is real name with no spaces, {3} is real name with dash instead of spaces." + }, + "type": { + "type": "string", + "enum": [ + null, + "user", + "device" + ], + "default": null, + "description": "Indicate if this button should be shown in the user or device type. If omitted, it will be displayed in both." + } }, - "required": [ "name", "url" ] + "required": [ + "name", + "url" + ] } }, "deviceMeshRouterLinks": { - "rdp": { "type": "boolean", "default": true, "description": "Display a RDP link in the device tab when supported." }, - "ssh": { "type": "boolean", "default": true, "description": "Display a SSH link in the device tab when supported." }, - "scp": { "type": "boolean", "default": true, "description": "Display a SCP link in the device tab when supported." }, - "extralinks": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": false, - "required": [ "name", "protocol", "port" ], - "properties": { - "name": { - "description": "Name of the link to be displayed on the web site.", - "type": "string" - }, - "protocol": { - "description": "Protocol. Valid values are: custom,http,https,rdp,ssh,scp,mcrdesktop,mcrfiles.", - "type": "string" - }, - "port": { - "description": "The port on the remote device.", - "default": 0, - "minimum": 0, - "maximum": 65535, - "type": "integer" - }, - "ip": { - "description": "Target IP address. If not specified, the target of the connection is the remote device running the MeshAgent.", - "type": "string" - }, - "localport": { - "description": "The local port MeshCentral Router would bind to. By default, a random available port is used.", - "default": 0, - "minimum": 0, - "maximum": 65535, - "type": "integer" - }, - "filter": { - "description": "Array of node// or mesh// or tag: strings. When set, the link will only show up for the specified devices, device groups or device tag.", - "type": "array", - "items": { "type": "string" } + "type": "object", + "properties": { + "rdp": { + "type": "boolean", + "default": true, + "description": "Display a RDP link in the device tab when supported." + }, + "ssh": { + "type": "boolean", + "default": true, + "description": "Display a SSH link in the device tab when supported." + }, + "scp": { + "type": "boolean", + "default": true, + "description": "Display a SCP link in the device tab when supported." + }, + "extralinks": { + "type": "array", + "items": { + "type": "object", + "required": [ + "name", + "protocol", + "port" + ], + "properties": { + "name": { + "description": "Name of the link to be displayed on the web site.", + "type": "string" + }, + "protocol": { + "description": "Protocol. Valid values are: custom,http,https,rdp,ssh,scp,mcrdesktop,mcrfiles.", + "type": "string" + }, + "port": { + "description": "The port on the remote device.", + "default": 0, + "minimum": 0, + "maximum": 65535, + "type": "integer" + }, + "ip": { + "description": "Target IP address. If not specified, the target of the connection is the remote device running the MeshAgent.", + "type": "string" + }, + "localport": { + "description": "The local port MeshCentral Router would bind to. By default, a random available port is used.", + "default": 0, + "minimum": 0, + "maximum": 65535, + "type": "integer" + }, + "filter": { + "description": "Array of node// or mesh// or tag: strings. When set, the link will only show up for the specified devices, device groups or device tag.", + "type": "array", + "items": { + "type": "string" + } + } } } } } }, + "assistantTypeAgentInvite": { + "type": "integer", + "default": 0, + "description": "0 = System Tray, Connect on user request, 1 = System Tray, Always Connected, 2 = Application, Connect on user request, 3 = Application, Always connected, 4 = System Tray, Monitor Only" + }, "certUrl": { "type": "string", "format": "uri", - "description": "https url when to get the TLS certificate that MeshAgent's will see when connecting to this server. This setting is used when a reverse proxy like NGINX is used in front of MeshCentral." + "description": "https url when to get the TLS certificate that MeshAgent's will see when connecting to this server. This setting is used when a reverse proxy like NGINX is used in front of MeshCentral. You can set this to file:// but it must be followed by the full path to the certificate file." }, "myServer": { - "type": [ "object", "boolean" ], - "additionalProperties": false, + "type": [ + "object", + "boolean" + ], "properties": { - "Backup": { "type": "boolean", "default": true, "description": "Allows administrators to backup the server from the My Server tab. This option can only enabled when the NeDB database is in use. For other databases, this option disabled and the setting is ignored." }, - "Restore": { "type": "boolean", "default": true, "description": "Allows administrators to restore the server from the My Server tab. This option can only enabled when the NeDB database is in use. For other databases, this option disabled and the setting is ignored." }, - "Upgrade": { "type": "boolean", "default": true, "description": "Allows administrators to update the server from the My Server tab." }, - "ErrorLog": { "type": "boolean", "default": true, "description": "Allows administrators to see the server crash log the server from the My Server tab." }, - "Console": { "type": "boolean", "default": true, "description": "Allows administrators to access the server console from the My Server tab." }, - "Trace": { "type": "boolean", "default": true, "description": "Allows administrators to access the server trace tab from from the My Server tab." } + "Backup": { + "type": "boolean", + "default": true, + "description": "Allows administrators to backup the server from the My Server tab. This option can only enabled when the NeDB database is in use. For other databases, this option disabled and the setting is ignored." + }, + "Restore": { + "type": "boolean", + "default": true, + "description": "Allows administrators to restore the server from the My Server tab. This option can only enabled when the NeDB database is in use. For other databases, this option disabled and the setting is ignored." + }, + "Upgrade": { + "type": "boolean", + "default": true, + "description": "Allows administrators to update the server from the My Server tab." + }, + "ErrorLog": { + "type": "boolean", + "default": true, + "description": "Allows administrators to see the server crash log the server from the My Server tab." + }, + "Console": { + "type": "boolean", + "default": true, + "description": "Allows administrators to access the server console from the My Server tab." + }, + "Trace": { + "type": "boolean", + "default": true, + "description": "Allows administrators to access the server trace tab from from the My Server tab." + }, + "Config": { + "type": "boolean", + "default": true, + "description": "Allows administrators remotely view server configuration on the My Server tab." + } } }, "passwordRequirements": { "type": "object", "properties": { - "min": { "type": "integer", "description": "Minimum number of characters allowed for the account password." }, - "max": { "type": "integer", "description": "Maximum number of characters allowed for the account password." }, - "upper": { "type": "integer", "description": "Minimum number of upper case characters required in the password." }, - "lower": { "type": "integer", "description": "Minimum number of lower case characters required in the password." }, - "numeric": { "type": "integer", "description": "Minimum number of numeric characters required in the password." }, - "nonalpha": { "type": "integer", "description": "Minimum number of non-alpha-numeric characters required in the password." }, - "reset": { "type": "integer", "description": "Number of days after which the user is required to change the account password." }, - "email2factor": { "type": "boolean", "default": true, "description": "Set to false to disable email 2FA." }, - "sms2factor": { "type": "boolean", "default": true, "description": "Set to false to disable SMS 2FA." }, - "push2factor": { "type": "boolean", "default": true, "description": "Set to false to disable push notification 2FA." }, - "otp2factor": { "type": "boolean", "default": true, "description": "Set to false to disable one-time-password 2FA." }, - "msg2factor": { "type": "boolean", "default": true, "description": "Set to false to disable user messaging 2FA." }, - "backupcode2factor": { "type": "boolean", "default": true, "description": "Set to false to disable 2FA backup codes." }, - "single2factorWarning": { "type": "boolean", "default": true, "description": "Set to false to disable single 2FA warning." }, - "lock2factor": { "type": "boolean", "default": false, "description": "When set to true, prevents any changes to 2FA." }, - "force2factor": { "type": "boolean", "default": false, "description": "Requires that all accounts setup 2FA." }, - "skip2factor": { "type": "string", "description": "IP addresses where 2FA login is skipped, for example: 127.0.0.1,192.168.2.0/24" }, - "oldPasswordBan": { "type": "integer", "description": "Number of old passwords the server should remember and not allow the user to switch back to." }, - "banCommonPasswords": { "type": "boolean", "default": false, "description": "Uses WildLeek to block use of the 10000 most commonly used passwords." }, - "loginTokens": { "type": [ "boolean", "array" ], "default": true, "description": "Allows users to create alternative username/passwords for their account. Set to false to disallow all users, or set to a userid array to only all some users." }, - "twoFactorTimeout": { "type": "integer", "default": 300, "description": "Maximum about of time the to wait for a 2FA token on the login page in seconds." }, - "autofido2fa": { "type": "boolean", "default": false, "description": "If true and user account has FIDO key setup, 2FA login screen will automatically request FIDO 2FA." }, - "maxfidokeys": { "type": "integer", "default": null, "description": "Maximum number of FIDO/YubikeyOTP hardware 2FA keys that can be setup in a user account." }, - "allowaccountreset": { "type": "boolean", "default": true, "description": "If set to false, the account reset option on the login screen will not be available to users." } + "min": { + "type": "integer", + "description": "Minimum number of characters allowed for the account password." + }, + "max": { + "type": "integer", + "description": "Maximum number of characters allowed for the account password." + }, + "upper": { + "type": "integer", + "description": "Minimum number of upper case characters required in the password." + }, + "lower": { + "type": "integer", + "description": "Minimum number of lower case characters required in the password." + }, + "numeric": { + "type": "integer", + "description": "Minimum number of numeric characters required in the password." + }, + "nonalpha": { + "type": "integer", + "description": "Minimum number of non-alpha-numeric characters required in the password." + }, + "reset": { + "type": "integer", + "description": "Number of days after which the user is required to change the account password." + }, + "email2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable email 2FA." + }, + "sms2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable SMS 2FA." + }, + "duo2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable Duo 2FA." + }, + "push2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable push notification 2FA." + }, + "otp2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable one-time-password 2FA." + }, + "msg2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable user messaging 2FA." + }, + "backupcode2factor": { + "type": "boolean", + "default": true, + "description": "Set to false to disable 2FA backup codes." + }, + "single2factorWarning": { + "type": "boolean", + "default": true, + "description": "Set to false to disable single 2FA warning." + }, + "lock2factor": { + "type": "boolean", + "default": false, + "description": "When set to true, prevents any changes to 2FA." + }, + "force2factor": { + "type": "boolean", + "default": false, + "description": "Requires that all accounts setup 2FA." + }, + "skip2factor": { + "type": "string", + "description": "IP addresses where 2FA login is skipped, for example: 127.0.0.1,192.168.2.0/24" + }, + "oldPasswordBan": { + "type": "integer", + "description": "Number of old passwords the server should remember and not allow the user to switch back to." + }, + "banCommonPasswords": { + "type": "boolean", + "default": false, + "description": "Uses WildLeek to block use of the 10000 most commonly used passwords." + }, + "loginTokens": { + "type": [ + "boolean", + "array" + ], + "default": true, + "description": "Allows users to create alternative username/passwords for their account. Set to false to disallow all users, or set to a userid array to only allow some users." + }, + "twoFactorTimeout": { + "type": "integer", + "default": 300, + "description": "Maximum about of time to wait for a 2FA token on the login page in seconds." + }, + "autofido2fa": { + "type": "boolean", + "default": false, + "description": "If true and user account has FIDO key setup, 2FA login screen will automatically request FIDO 2FA." + }, + "maxfidokeys": { + "type": "integer", + "default": null, + "description": "Maximum number of FIDO/YubikeyOTP hardware 2FA keys that can be setup in a user account." + }, + "allowaccountreset": { + "type": "boolean", + "default": true, + "description": "If set to false, the account reset option on the login screen will not be available to users." + } } }, - "twoFactorCookieDurationDays": { "type": "integer", "default": 30, "description": "Number of days that a user is allowed to remember this device for when completing 2FA. Set this to 0 to remove this option." }, - "auth": { "type": "string", "default": null, "enum": [null, "sspi", "ldap"], "description": "Type of user authentication to use, this can be SSPI on Windows or LDAP. If not set, username/password is used." }, - "ldapUserKey": { "type": "string", "default": null, "description": "The LDAP value to use as a user's unique account identifier. Use \"ldapUserKey\" or \"ldapUserBinaryKey\"." }, - "ldapUserBinaryKey": { "type": "string", "default": "objectSid", "description": "The LDAP value to use as a user's unique account identifier, when specified in this field, the values will be HEX converted." }, - "ldapUserName": { "type": "string", "default": "displayName", "description": "The LDAP value to use for the user name, you can also compose the name by setting this value to, for example: \"{{{givenName}}} {{{sn}}}\"" }, - "ldapUserEmail": { "type": "string", "default": "mail", "description": "The LDAP value to use for the user's email address." }, - "ldapUserRealName": { "type": "string", "default": "name", "description": "The LDAP value to use for the user's real name, you can also compose the name by setting this value to, for example: \"{{{givenName}}} {{{sn}}}\"" }, - "ldapUserPhoneNumber": { "type": "string", "default": "telephoneNumber", "description": "The LDAP value to use for the user's phone number." }, - "ldapUserImage": { "type": "string", "default": "thumbnailPhoto", "description": "The LDAP value to use for the user's image." }, - "ldapSaveUserToFile": { "type": "string", "default": null, "description": "When set to a filename, for example c:\\temp\\ldapusers.txt, MeshCentral will save the LDAP user object to this file each time a user logs in. This is used for debugging LDAP issues." }, - "ldapUserGroups": { "type": "string", "default": "memberOf", "description": "The LDAP value to use for the user's group memberships." }, + "twoFactorCookieDurationDays": { + "type": "integer", + "default": 30, + "description": "Number of days that a user is allowed to remember this device for when completing 2FA. Set this to 0 to remove this option." + }, + "auth": { + "type": "string", + "default": null, + "enum": [ + null, + "sspi", + "ldap" + ], + "description": "Type of user authentication to use, this can be SSPI on Windows or LDAP. If not set, username/password is used." + }, + "ldapUserKey": { + "type": "string", + "default": null, + "description": "The LDAP value to use as a user's unique account identifier. Use \"ldapUserKey\" or \"ldapUserBinaryKey\"." + }, + "ldapUserBinaryKey": { + "type": "string", + "default": "objectSid", + "description": "The LDAP value to use as a user's unique account identifier, when specified in this field, the values will be HEX converted." + }, + "ldapUserName": { + "type": "string", + "default": "displayName", + "description": "The LDAP value to use for the user name, you can also compose the name by setting this value to, for example: \"{{{givenName}}} {{{sn}}}\"" + }, + "ldapUserEmail": { + "type": "string", + "default": "mail", + "description": "The LDAP value to use for the user's email address." + }, + "ldapUserRealName": { + "type": "string", + "default": "name", + "description": "The LDAP value to use for the user's real name, you can also compose the name by setting this value to, for example: \"{{{givenName}}} {{{sn}}}\"" + }, + "ldapUserPhoneNumber": { + "type": "string", + "default": "telephoneNumber", + "description": "The LDAP value to use for the user's phone number." + }, + "ldapUserImage": { + "type": "string", + "default": "thumbnailPhoto", + "description": "The LDAP value to use for the user's image." + }, + "ldapSaveUserToFile": { + "type": "string", + "default": null, + "description": "When set to a filename, for example c:\\temp\\ldapusers.txt, MeshCentral will save the LDAP user object to this file each time a user logs in. This is used for debugging LDAP issues." + }, + "ldapUserGroups": { + "type": "string", + "default": "memberOf", + "description": "The LDAP value to use for the user's group memberships." + }, "ldapSyncWithUserGroups": { - "type": [ "boolean", "object" ], + "type": [ + "boolean", + "object" + ], "default": false, "description": "When set to true or set to an object, MeshCentral will synchronize LDAP user memberships to MeshCentral user groups.", - "additionalProperties": false, "properties": { "filter": { - "type": [ "string", "array" ], + "type": [ + "string", + "array" + ], "default": null, "description": "When set to a string or array of strings, only LDAP membership groups that includes one of the strings will be synchronized with MeshCentral user groups." } } }, "ldapSiteAdminGroups": { - "type": [ "string", "array" ], + "type": [ + "string", + "array" + ], "default": null, "description": "When set to a list of LDAP groups, users that are part of one of these groups will be set a site administrator, otherwise site administrator rights will be removed." }, - "ldapUserRequiredGroupMembership": { "type": [ "string", "array" ], "default": null, "description": "A list of LDAP groups. Users must be part of at least one of these groups to allow login. If null, all users are allowed to login." }, - "ldapOptions": { "type": "object", "description": "LDAP options passed to ldapauth-fork" }, - "agentInviteCodes": { "type": "boolean", "default": false, "description": "Enabled a feature where you can set one or more invitation codes in a device group. You can then give a invitation link to users who can use it to download the agent." }, - "agentNoProxy": { "type": "boolean", "default": false, "description": "When enabled, all newly installed MeshAgents will be instructed to no use a HTTP/HTTPS proxy even if one is configured on the remote system" }, + "ldapUserRequiredGroupMembership": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "A list of LDAP groups. Users must be part of at least one of these groups to allow login. If null, all users are allowed to login." + }, + "ldapOptions": { + "type": "object", + "description": "LDAP options passed to ldapauth-fork" + }, + "hidePowerTimeline": { + "type": "boolean", + "default": false, + "description": "When enabled, this will hide the power timeline in the web ui" + }, + "showNotesPanel": { + "type": "boolean", + "default": false, + "description": "When enabled, this will show the notes panel in the device view" + }, + "userSessionsSort": { + "type": "string", + "default": "SessionId", + "description": "Arrange the Connect sessions offered when multiple Terminal Sessions are present by 'SessionId', 'StationName' or 'Username' with 'SessionId' as the default sorting criteria." + }, + "agentInviteCodes": { + "type": "boolean", + "default": false, + "description": "Enabled a feature where you can set one or more invitation codes in a device group. You can then give a invitation link to users who can use it to download the agent." + }, + "agentNoProxy": { + "type": "boolean", + "default": false, + "description": "When enabled, all newly installed MeshAgents will be instructed to no use a HTTP/HTTPS proxy even if one is configured on the remote system" + }, "agentTag": { "type": "object", "description": "This section is used to indicate if parts of the meshagent.tag file should be used to set server-side device properties.", - "additionalProperties": false, "properties": { - "ServerName": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerName:name. 0=Ignore, 1=Set." }, - "ServerDesc": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerDesc:desc. 0=Ignore, 1=Set, 2=SetIfEmpty." }, - "ServerTags": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerTags:tag1,tag2,tag3. 0=Ignore, 1=Set, 2=SetIfEmpty, 3=Append." } + "ServerName": { + "type": "integer", + "default": 0, + "description": "Action taken if one of the lines in meshagent.tag contains ~ServerName:name. 0=Ignore, 1=Set." + }, + "ServerDesc": { + "type": "integer", + "default": 0, + "description": "Action taken if one of the lines in meshagent.tag contains ~ServerDesc:desc. 0=Ignore, 1=Set, 2=SetIfEmpty." + }, + "ServerTags": { + "type": "integer", + "default": 0, + "description": "Action taken if one of the lines in meshagent.tag contains ~ServerTags:tag1,tag2,tag3. 0=Ignore, 1=Set, 2=SetIfEmpty, 3=Append." + } } }, - "geoLocation": { "type": "boolean", "default": false, "description": "Enables the geo-location feature and device location map in the user interface, this feature is not being worked on." }, - "novnc": { "type": "boolean", "default": true, "description": "When enabled, activates the built-in web-based VNC client." }, - "mstsc": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based RDP client." }, - "ssh": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based SSH client." }, - "webEmailsPath": { "type": "string", "description": "Path where to find custom email templates for this domain." }, - "customUI": { "type": "object" }, + "lockAgentDownload": { + "type": "boolean", + "default": false, + "description": "When enabled, MeshCentral will block all downloads of MeshAgent including install scripts, if the user is not logged in" + }, + "geoLocation": { + "type": "boolean", + "default": false, + "description": "Enables the geo-location feature and device location map in the user interface, this feature is not being worked on." + }, + "ipLocation": { + "type": "boolean", + "default": false, + "description": "When enabled, the remote agents will submit there approximate location to MeshCentral, Use in combination with \"geoLocation\"." + }, + "novnc": { + "type": "boolean", + "default": true, + "description": "When enabled, activates the built-in web-based VNC client." + }, + "mstsc": { + "type": "boolean", + "default": true, + "description": "When enabled, activates the built-in web-based RDP client." + }, + "ssh": { + "type": "boolean", + "default": false, + "description": "When enabled, activates the built-in web-based SSH client." + }, + "webEmailsPath": { + "type": "string", + "description": "Path where to find custom email templates for this domain." + }, + "customUI": { + "type": "object" + }, "consentMessages": { "type": "object", "description": "This section is used to customize user consent prompts, these show up when asking if a remote session is allowed or not.", - "additionalProperties": false, "properties": { - "Title": { "type": "string" }, - "Desktop": { "type": "string" }, - "Terminal": { "type": "string" }, - "Files": { "type": "string" }, - "consentTimeout": { "type": "integer", "default": 30, "description": "How long in seconds to show the user consent dialog box." }, - "autoAcceptOnTimeout": { "type": "boolean", "default": false, "description": "If true, user consent is accepted after the timeout." } + "Title": { + "type": "string" + }, + "Desktop": { + "type": "string" + }, + "Terminal": { + "type": "string" + }, + "Files": { + "type": "string" + }, + "consentTimeout": { + "type": "integer", + "default": 30, + "description": "How long in seconds to show the user consent dialog box." + }, + "autoAcceptOnTimeout": { + "type": "boolean", + "default": false, + "description": "If true, user consent is accepted after the timeout." + }, + "autoAcceptIfNoUser": { + "type": "boolean", + "default": false, + "description": "If true, user consent is accepted if no user is logged in." + }, + "oldStyle": { + "type": "boolean", + "default": false, + "description": "If true, user consent will be shown in an old style prompt box rather than the new style consent-box." + } } }, "notificationMessages": { "type": "object", - "additionalProperties": false, "description": "This section is user to customize user notifications when a remote desktop, terminal or file session is connected to a remote system.", "properties": { - "Title": { "type": "string" }, - "Desktop": { "type": "string" }, - "Terminal": { "type": "string" }, - "Files": { "type": "string" } + "Title": { + "type": "string" + }, + "Desktop": { + "type": "string" + }, + "Terminal": { + "type": "string" + }, + "Files": { + "type": "string" + } } }, "agentCustomization": { "type": "object", - "additionalProperties": false, "description": "Use this section to customize the agent branding.", "properties": { - "displayName": { "type": "string", "default": "MeshCentral Agent", "description": "The name of the agent as displayed to the user." }, - "description": { "type": "string", "default": "Mesh Agent background service", "description": "The description of the agent as displayed to the user." }, - "companyName": { "type": "string", "default": "Mesh Agent", "description": "This will be used as the path to install the agent, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's." }, - "serviceName": { "type": "string", "default": "Mesh Agent", "description": "The name of the background service, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's but should be set to an all lower case, no space string." }, - "installText": { "type": "string", "default": null, "description": "Text string to show in the agent installation dialog box." }, - "image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in the MeshCentral Agent installation dialog, image should be square and from 64x64 to 200x200." }, - "fileName": { "type": "string", "default": "meshagent", "description": "The agent filename." }, - "foregroundColor": { "type": "string", "default": null, "description": "Foreground text color, valid values are RBG in format 0,0,0 to 255,255,255 or format #000000 to #FFFFFF." }, - "backgroundColor": { "type": "string", "default": null, "description": "Background color, valid values are RBG in format 0,0,0 to 255,255,255 or format #000000 to #FFFFFF." } + "displayName": { + "type": "string", + "default": "MeshCentral Agent", + "description": "The name of the agent as displayed to the user." + }, + "description": { + "type": "string", + "default": "Mesh Agent background service", + "description": "The description of the agent as displayed to the user." + }, + "companyName": { + "type": "string", + "default": "Mesh Agent", + "description": "This will be used as the path to install the agent, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's." + }, + "serviceName": { + "type": "string", + "default": "Mesh Agent", + "description": "The name of the background service, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's but should be set to an all lower case, no space string." + }, + "installText": { + "type": "string", + "default": null, + "description": "Text string to show in the agent installation dialog box." + }, + "image": { + "type": "string", + "default": null, + "description": "The filename of a image file in .png format located in meshcentral-data to display in the MeshCentral Agent installation dialog, image should be square and from 64x64 to 200x200." + }, + "fileName": { + "type": "string", + "default": "meshagent", + "description": "The agent filename." + }, + "foregroundColor": { + "type": "string", + "default": null, + "description": "Foreground text color, valid values are RBG in format 0,0,0 to 255,255,255 or format #000000 to #FFFFFF." + }, + "backgroundColor": { + "type": "string", + "default": null, + "description": "Background color, valid values are RBG in format 0,0,0 to 255,255,255 or format #000000 to #FFFFFF." + } } }, "agentFileInfo": { "type": "object", - "additionalProperties": false, "description": "Use this section to set resource metadata of the Windows agents prior to signing. In Windows, you can right-click and select properties to view these values.", "properties": { - "icon": { "type": "string", "description": "Sets the agent icon, this is the name of a .ico file with the file placed in the meshcentral-data folder." }, - "fileDescription": { "type": "string", "description": "Executable file description." }, - "fileVersion": { "type": "string", "description": "Executable file version, in the form of 'n.n.n.n', for example: '1.2.3.4'." }, - "internalName": { "type": "string", "description": "Executable internal name." }, - "legalCopyright": { "type": "string", "description": "Executable legal copyright." }, - "originalFilename": { "type": "string", "description": "Executable original file name." }, - "productName": { "type": "string", "description": "Executable product name." }, - "productVersion": { "type": "string", "description": "Executable product version. Any string format will work, but a alphabetic character is required for this value to show correctly in the Windows property box. For example: 'v1.2.3.4' will work, but '1.2.3.4' will not." } + "icon": { + "type": "string", + "description": "Sets the agent icon, this is the name of a .ico file with the file placed in the meshcentral-data folder." + }, + "fileDescription": { + "type": "string", + "description": "Executable file description." + }, + "fileVersion": { + "type": "string", + "description": "Executable file version, in the form of 'n.n.n.n', for example: '1.2.3.4'." + }, + "internalName": { + "type": "string", + "description": "Executable internal name." + }, + "legalCopyright": { + "type": "string", + "description": "Executable legal copyright." + }, + "originalFilename": { + "type": "string", + "description": "Executable original file name." + }, + "productName": { + "type": "string", + "description": "Executable product name." + }, + "productVersion": { + "type": "string", + "description": "Executable product version. Any string format will work, but a alphabetic character is required for this value to show correctly in the Windows property box. For example: 'v1.2.3.4' will work, but '1.2.3.4' will not." + } } }, "assistantCustomization": { "type": "object", - "additionalProperties": false, "description": "Use this section to customize the MeshCentral Assistant.", "properties": { - "title": { "type": "string", "default": "MeshCentral Assistant", "description": "Name to show as MeshCentral Assistant dialog title." }, - "image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in MeshCentral Assistant, image should be square and from 64x64 to 128x128." }, - "fileName": { "type": "string", "default": "meshagent", "description": "The MeshCentral Assistant filename." } + "title": { + "type": "string", + "default": "MeshCentral Assistant", + "description": "Name to show as MeshCentral Assistant dialog title." + }, + "image": { + "type": "string", + "default": null, + "description": "The filename of a image file in .png format located in meshcentral-data to display in MeshCentral Assistant, image should be square and from 64x64 to 128x128." + }, + "fileName": { + "type": "string", + "default": "meshagent", + "description": "The MeshCentral Assistant filename." + } } }, "androidCustomization": { "type": "object", - "additionalProperties": false, "description": "Use this section to customize the MeshCentral Agent for Android.", "properties": { - "title": { "type": "string", "default": "MeshCentral Agent", "description": "Displayed on top of the MeshCentral Agent for Android." }, - "subtitle": { "type": "string", "default": null, "description": "Subtitle displayed until the title on the toolbar." }, - "image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in MeshCentral Agent for Android, image should be square and from 64x64 to 128x128." } + "title": { + "type": "string", + "default": "MeshCentral Agent", + "description": "Displayed on top of the MeshCentral Agent for Android." + }, + "subtitle": { + "type": "string", + "default": null, + "description": "Subtitle displayed until the title on the toolbar." + }, + "image": { + "type": "string", + "default": null, + "description": "The filename of a image file in .png format located in meshcentral-data to display in MeshCentral Agent for Android, image should be square and from 64x64 to 128x128." + } } }, - "ipBlockedUserRedirect" : { "type": "string", "default": null, "description": "If set, a user from a banned IP address will be redirected to this URL." }, - "userRequiredHttpHeader": { "type": "object", "default": null, "description": "When set, requires that a browser request have set HTTP header to allow user login. Example: \"{ \"Sec-Fetch-Dest\": \"iframe\" }\"" }, - "userAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "userBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentAllowedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "agentBlockedIP": { "type": [ "string", "array" ], "default": null, "description": "When set, agents from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\"" }, - "userSessionIdleTimeout": { "type": "integer", "default": null, "description": "When set, idle users will be disconnected after a set amounts of minutes." }, + "ipBlockedUserRedirect": { + "type": "string", + "default": null, + "description": "If set, a user from a banned IP address will be redirected to this URL." + }, + "userRequiredHttpHeader": { + "type": "object", + "default": null, + "description": "When set, requires that a browser request have set HTTP header to allow user login. Example: \"{ \"Sec-Fetch-Dest\": \"iframe\" }\"" + }, + "userAllowedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, only users from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:userAllowedIP.txt\"" + }, + "userBlockedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, users from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:userBlockedIP.txt\"" + }, + "agentAllowedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, only agents from allowed IP address ranges can connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:agentAllowedIP.txt\"" + }, + "agentBlockedIP": { + "type": [ + "string", + "array" + ], + "default": null, + "description": "When set, agents from these denied IP address ranges will not be able to connect to the server. Example: \"192.168.2.100,192.168.1.0/24\" \"file:agentBlockedIP.txt\"" + }, + "userSessionIdleTimeout": { + "type": "integer", + "default": null, + "description": "When set, idle users will be disconnected after a set amounts of minutes." + }, + "logoutOnIdleSessionTimeout": { + "type": "boolean", + "default": true, + "description": "Determines whether MeshCentral should logout after the session idle timeout elapsed or should just disconnect remote desktop, terminal and files." + }, "userConsentFlags": { "type": "object", - "additionalProperties": false, "description": "Use this section to require user consent for this domain.", "properties": { - "desktopnotify": { "type": "boolean", "default": false, "description": "Enable desktop notification for this domain." }, - "terminalnotify": { "type": "boolean", "default": false, "description": "Enable terminal notification for this domain." }, - "filenotify": { "type": "boolean", "default": false, "description": "Enable files notification for this domain." }, - "desktopprompt": { "type": "boolean", "default": false, "description": "Enable desktop prompt for this domain." }, - "terminalprompt": { "type": "boolean", "default": false, "description": "Enable terminal user prompt for this domain." }, - "fileprompt": { "type": "boolean", "default": false, "description": "Enable files prompt for this domain." }, - "desktopprivacybar": { "type": "boolean", "default": false, "description": "Enable remote desktop privacy bar for this domain." } + "desktopnotify": { + "type": "boolean", + "default": false, + "description": "Enable desktop notification for this domain." + }, + "terminalnotify": { + "type": "boolean", + "default": false, + "description": "Enable terminal notification for this domain." + }, + "filenotify": { + "type": "boolean", + "default": false, + "description": "Enable files notification for this domain." + }, + "desktopprompt": { + "type": "boolean", + "default": false, + "description": "Enable desktop prompt for this domain." + }, + "terminalprompt": { + "type": "boolean", + "default": false, + "description": "Enable terminal user prompt for this domain." + }, + "fileprompt": { + "type": "boolean", + "default": false, + "description": "Enable files prompt for this domain." + }, + "desktopprivacybar": { + "type": "boolean", + "default": false, + "description": "Enable remote desktop privacy bar for this domain." + } } }, - "urlSwitching": { "type": "boolean", "default": true, "description": "When users navigate thru the web interface, the URL on top will change to point to the current screen. This allows a user to refresh or bookmark the URL and come back to the correct screen. Setting false here will disable this feature." }, - "desktopPrivacyBarText": { "type": "string", "description": "This is the text that will be shown in the remote desktop privacy bar. You can use {0} to display the account realname or {1} to display the account identifier in the string." }, + "urlSwitching": { + "type": "boolean", + "default": true, + "description": "When users navigate thru the web interface, the URL on top will change to point to the current screen. This allows a user to refresh or bookmark the URL and come back to the correct screen. Setting false here will disable this feature." + }, + "desktopPrivacyBarText": { + "type": "string", + "description": "This is the text that will be shown in the remote desktop privacy bar. You can use {0} to display the account realname or {1} to display the account identifier in the string." + }, "limits": { "type": "object", - "additionalProperties": false, "properties": { - "MaxDevices": { "type": "integer", "default": null, "description": "Maximum number of devices in this domain." }, - "MaxUserAccounts": { "type": "integer", "default": null, "description": "Maximum number of devices in this domain." }, - "MaxUserSessions": { "type": "integer", "default": null, "description": "Maximum number of user sessions that can connect to this server for this domain." }, - "MaxAgentSessions": { "type": "integer", "default": null, "description": "Maximum number of agents that can connect to this server for this domain." }, - "MaxSingleUserSessions": { "type": "integer", "default": null, "description": "Maximum number of sessions a single user can have. Each time a user opens a new browser tab or opens a new browser on a different computer, a new user session is created." } + "MaxDevices": { + "type": "integer", + "default": null, + "description": "Maximum number of devices in this domain." + }, + "MaxUserAccounts": { + "type": "integer", + "default": null, + "description": "Maximum number of devices in this domain." + }, + "MaxUserSessions": { + "type": "integer", + "default": null, + "description": "Maximum number of user sessions that can connect to this server for this domain." + }, + "MaxAgentSessions": { + "type": "integer", + "default": null, + "description": "Maximum number of agents that can connect to this server for this domain." + }, + "MaxSingleUserSessions": { + "type": "integer", + "default": null, + "description": "Maximum number of sessions a single user can have. Each time a user opens a new browser tab or opens a new browser on a different computer, a new user session is created." + } } }, "files": { "type": "object", "description": "Values that affect the files feature", "properties": { - "sftpConnect" : { "type": "boolean", "default": true, "description": "When false, removes the 'SFTP Connect' button from the files tab unless this is the only possible option." } + "sftpConnect": { + "type": "boolean", + "default": true, + "description": "When false, removes the 'SFTP Connect' button from the files tab unless this is the only possible option." + } } }, "terminal": { "type": "object", "description": "Values that affect the terminal feature", "properties": { - "sshConnect" : { "type": "boolean", "default": true, "description": "When false, removes the 'SSH Connect' button from the terminal tab unless this is the only possible option." }, + "sshConnect": { + "type": "boolean", + "default": true, + "description": "When false, removes the 'SSH Connect' button from the terminal tab unless this is the only possible option." + }, "linuxShell": { "type": "string", - "enum": [ "any", "root", "user", "login" ], + "enum": [ + "any", + "root", + "user", + "login" + ], "default": "any", - "description": "Indicate what terminal options are available when the user clicks the right mouse button on the terminal connect button." + "description": "Indicates the default linux terminal thats used when the user clicks the terminal connect button and disables the right mouse button on the terminal connect button when this is set." }, "launchCommand": { "type": "object", "description": "Indicate what string the agent must write to the shell after starting a terminal session", - "linux": { "type": "string", "default": " alias ls=\\'ls --color=auto\\';clear\\n", "description": "String to write after opening a Linux terminal." }, - "darwin": { "type": "string", "default": null, "description": "String to write after opening a macOS terminal." }, - "freebsd": { "type": "string", "default": null, "description": "String to write after opening a FreeBSD terminal." } + "linux": { + "type": "string", + "default": " alias ls=\\'ls --color=auto\\';clear\\n", + "description": "String to write after opening a Linux terminal." + }, + "darwin": { + "type": "string", + "default": null, + "description": "String to write after opening a macOS terminal." + }, + "freebsd": { + "type": "string", + "default": null, + "description": "String to write after opening a FreeBSD terminal." + } } } }, @@ -742,22 +2332,32 @@ "description": "List of local network Intel AMT scanning options offered in the user interface. For example [\"LabNetwork 192.168.15.0/23\", \"SalesNetwork 192.168.8.0/24\"].", "type": "array", "default": null, - "items": { "type": "string" } + "items": { + "type": "string" + } }, "amtManager": { "type": "object", - "additionalProperties": false, "description": "Information passed to the AMT manager module that impacts all Intel AMT device managed within this domain.", "properties": { - "TlsConnections": { "type": "boolean", "default": true, "description": "When set to false, MeshCentral will use TLS to connect to Intel AMT, this is not recommended." }, - "TlsAcmActivation": { "type": "boolean", "default": false, "description": "When set to false, MeshCentral will not attempt a TLS ACM activation on Intel AMT v14+" }, + "TlsConnections": { + "type": "boolean", + "default": true, + "description": "When set to false, MeshCentral will NOT use TLS to connect to Intel AMT, this is not recommended." + }, + "TlsAcmActivation": { + "type": "boolean", + "default": false, + "description": "When set to true, MeshCentral will attempt a TLS ACM activation on Intel AMT v14+" + }, "AdminAccounts": { "description": "List of username and passwords to try when connecting to Intel AMT.", "type": "array", "items": { "type": "object", - "additionalProperties": false, - "required": [ "pass" ], + "required": [ + "pass" + ], "properties": { "user": { "description": "Intel AMT administrator username.", @@ -808,8 +2408,9 @@ "type": "array", "items": { "type": "object", - "additionalProperties": false, - "required": [ "ssid" ], + "required": [ + "ssid" + ], "properties": { "name": { "description": "WIFI profile name, if not specified the SSID is used.", @@ -822,13 +2423,23 @@ "authentication": { "description": "WIFI authentication.", "type": "string", - "enum": [ "wpa-psk", "wpa2-psk", "wpa-8021x", "wpa2-802.1x", "wpa3-sae-802.1x", "wpa3-owe-802.1x" ], + "enum": [ + "wpa-psk", + "wpa2-psk", + "wpa-8021x", + "wpa2-802.1x", + "wpa3-sae-802.1x", + "wpa3-owe-802.1x" + ], "default": "wpa2-psk" }, "encryption": { "description": "WIFI encryption.", "type": "string", - "enum": [ "ccmp-aes", "tkip-rc4" ], + "enum": [ + "ccmp-aes", + "tkip-rc4" + ], "default": "ccmp-aes" }, "password": { @@ -841,19 +2452,54 @@ "description": "802.1x settings for this WIFI profile. Only required if the WIFI authentication type has 802.1x", "default": null, "type": "object", - "additionalProperties": false, - "required": [ "authenticationProtocol" ], + "required": [ + "authenticationProtocol" + ], "properties": { "authenticationProtocol": { "description": "Identifies the authentication protocol used to authenticate the access requestor to the AAA server.", - "type": [ "integer", "string" ], - "enum": [ "EAP-TLS", "EAP-TTLS/MSCHAPv2", "PEAPv0/EAP-MSCHAPv2", "PEAPv1/EAP-GTC", "EAP-FAST/MSCHAPv2", "EAP-FAST/GTC", "EAP-MD5", "EAP-PSK", "EAP-SIM", "EAP-AKA", "EAP-FAST/TLS", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] + "type": [ + "integer", + "string" + ], + "enum": [ + "EAP-TLS", + "EAP-TTLS/MSCHAPv2", + "PEAPv0/EAP-MSCHAPv2", + "PEAPv1/EAP-GTC", + "EAP-FAST/MSCHAPv2", + "EAP-FAST/GTC", + "EAP-MD5", + "EAP-PSK", + "EAP-SIM", + "EAP-AKA", + "EAP-FAST/TLS", + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ] }, "serverCertificateNameComparison": { - "type": [ "integer", "string" ], + "type": [ + "integer", + "string" + ], "default": "FullName", "description": "Determines the comparison algorithm used between the ServerCertificateName value and the subject name field of the certificate presented by the AAA server.", - "enum": [ "FullName", "DomainSuffix", 2, 3 ] + "enum": [ + "FullName", + "DomainSuffix", + 2, + 3 + ] }, "serverCertificateName": { "type": "string", @@ -915,19 +2561,57 @@ "802.1x": { "description": "802.1x settings for the Intel AMT Wired interface. If set to false, any existing 802.1x wired profile will be removed from Intel AMT.", "default": null, - "type": [ "object", "boolean" ], - "additionalProperties": false, - "required": [ "authenticationProtocol" ], + "type": [ + "object", + "boolean" + ], + "required": [ + "authenticationProtocol" + ], "properties": { "authenticationProtocol": { "description": "Identifies the authentication protocol used to authenticate the access requestor to the AAA server.", - "type": [ "integer", "string" ], - "enum": [ "EAP-TLS", "EAP-TTLS/MSCHAPv2", "PEAPv0/EAP-MSCHAPv2", "PEAPv1/EAP-GTC", "EAP-FAST/MSCHAPv2", "EAP-FAST/GTC", "EAP-MD5", "EAP-PSK", "EAP-SIM", "EAP-AKA", "EAP-FAST/TLS", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] + "type": [ + "integer", + "string" + ], + "enum": [ + "EAP-TLS", + "EAP-TTLS/MSCHAPv2", + "PEAPv0/EAP-MSCHAPv2", + "PEAPv1/EAP-GTC", + "EAP-FAST/MSCHAPv2", + "EAP-FAST/GTC", + "EAP-MD5", + "EAP-PSK", + "EAP-SIM", + "EAP-AKA", + "EAP-FAST/TLS", + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ] }, "serverCertificateNameComparison": { - "type": [ "integer", "string" ], + "type": [ + "integer", + "string" + ], "description": "Determines the comparison algorithm used between the ServerCertificateName value and the subject name field of the certificate presented by the AAA server.", - "enum": [ "FullName", "DomainSuffix", 2, 3 ] + "enum": [ + "FullName", + "DomainSuffix", + 2, + 3 + ] }, "serverCertificateName": { "type": "string", @@ -983,87 +2667,234 @@ } } } - } + }, + "required": [ + "certs" + ] }, "amtAcmActivation": { "type": "object", - "additionalProperties": false, "properties": { - "log": { "type": "string" }, - "strictCommonName": { "type": "boolean", "default": false, "description": "When set to true, the certificate common name needs to match exactly the Intel AMT trusted FQDN or DHCP Option 15. If false, some flexibility may be given to the matching." }, + "log": { + "type": "string" + }, + "strictCommonName": { + "type": "boolean", + "default": false, + "description": "When set to true, the certificate common name needs to match exactly the Intel AMT trusted FQDN or DHCP Option 15. If false, some flexibility may be given to the matching." + }, "certs": { "type": "object", "additionalProperties": { "type": "object", - "additionalProperties": false, "properties": { - "certfiles": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "keyfile": { "type": "string" } + "certfiles": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "keyfile": { + "type": "string" + } }, - "required": [ "certfiles", "keyfile" ] + "required": [ + "certfiles", + "keyfile" + ] } } }, - "required": [ "certs" ] + "required": [ + "certs" + ] }, "redirects": { "type": "object", - "additionalProperties": { "type": "string" }, + "additionalProperties": { + "type": "string" + }, "description": "This is used to create HTTP redirections. For example setting \"redirects\": { \"example\":\"https://example.com\" } will make it so that anyone accessing /example on the server will get redirected to the specified URL." }, + "duo2factor": { + "type": "object", + "properties": { + "integrationkey": { + "type": "string", + "default": "", + "description": "Integration key from Duo" + }, + "secretkey": { + "type": "string", + "default": "", + "description": "Secret key from Duo" + }, + "apihostname": { + "type": "string", + "default": "", + "description": "API Hostname from Duo" + } + } + }, "yubikey": { "type": "object", - "additionalProperties": false, "properties": { - "id": { "type": "string" }, - "secret": { "type": "string" }, - "proxy": { "type": "string", "format": "uri" } + "id": { + "type": "string" + }, + "secret": { + "type": "string" + }, + "proxy": { + "type": "string", + "format": "uri" + } }, - "required": [ "id", "secret" ] + "required": [ + "id", + "secret" + ] + }, + "httpHeaders": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "agentConfig": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "default": null, + "description": "Key and values to add to the MeshAgent .msh file" + }, + "assistantConfig": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + }, + "default": null, + "description": "Key and values to add to the MeshCentral Assistant .msh file" + }, + "clipboardGet": { + "type": "boolean", + "default": true, + "description": "When false, users can't set the clipboard of a remove device." + }, + "clipboardSet": { + "type": "boolean", + "default": true, + "description": "When false, users can't get the clipboard of a remove device." + }, + "localSessionRecording": { + "type": "boolean", + "default": true, + "description": "When false, removes the local recording feature on remote desktop." }, - "httpHeaders": { "type": "object", "additionalProperties": { "type": "string" } }, - "agentConfig": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "default": null, "description": "Key and values to add to the MeshAgent .msh file" }, - "assistantConfig": { "type": "array", "uniqueItems": true, "items": { "type": "string" }, "default": null, "description": "Key and values to add to the MeshCentral Assistant .msh file" }, - "clipboardGet": { "type": "boolean", "default": true, "description": "When false, users can't set the clipboard of a remove device." }, - "clipboardSet": { "type": "boolean", "default": true, "description": "When false, users can't get the clipboard of a remove device." }, - "localSessionRecording": { "type": "boolean", "default": true, "description": "When false, removes the local recording feature on remote desktop." }, "sessionRecording": { "type": "object", - "additionalProperties": false, "properties": { - "onlySelectedUsers": { "type": "boolean", "default": false, "description": "When enabled, only device users with the session recording feature turned on will be recorded. When false, all users are recorded." }, - "onlySelectedUserGroups": { "type": "boolean", "default": false, "description": "When enabled, only device user groups with the session recording feature turned on will be recorded. When false, all users are recorded." }, - "onlySelectedDeviceGroups": { "type": "boolean", "default": false, "description": "When enabled, only device groups with the session recording feature turned on will be recorded. When false, all devices are recorded." }, - "filepath": { "type": "string", "description": "The file path where recording files are kept." }, - "index": { "type": "boolean", "default": false, "description": "If true, automatically index remote desktop recordings so that the plays can skip to any place in the file." }, - "maxRecordings": { "type": "integer", "default": null, "description": "Maximum number of recording files to keep." }, - "maxRecordingDays": { "type": "integer", "default": null, "description": "Maximum number of days to keep a recording." }, - "maxRecordingSizeMegabytes": { "type": "integer", "default": null, "description": "Maximum number of recordings in megabytes. Once exceed, remove the oldest recordings." }, - "protocols": { "type": "array", "uniqueItems": true, "items": { "type": "integer" }, "description": "This is an array: 1 = Terminal, 2 = Desktop, 5 = Files, 100 = Intel AMT WSMAN, 101 = Intel AMT Redirection, 200 = Messenger" } + "onlySelectedUsers": { + "type": "boolean", + "default": false, + "description": "When enabled, only device users with the session recording feature turned on will be recorded. When false, all users are recorded." + }, + "onlySelectedUserGroups": { + "type": "boolean", + "default": false, + "description": "When enabled, only device user groups with the session recording feature turned on will be recorded. When false, all users are recorded." + }, + "onlySelectedDeviceGroups": { + "type": "boolean", + "default": false, + "description": "When enabled, only device groups with the session recording feature turned on will be recorded. When false, all devices are recorded." + }, + "filepath": { + "type": "string", + "default": "meshcentral-recordings", + "description": "The file path where recording files are kept. The default is \"meshcentral-recordings\" which sits next to \"meshcentral-data\"." + }, + "index": { + "type": "boolean", + "default": false, + "description": "If true, automatically index remote desktop recordings so that the plays can skip to any place in the file." + }, + "maxRecordings": { + "type": "integer", + "default": null, + "description": "Maximum number of recording files to keep." + }, + "maxRecordingDays": { + "type": "integer", + "default": null, + "description": "Maximum number of days to keep a recording." + }, + "maxRecordingSizeMegabytes": { + "type": "integer", + "default": null, + "description": "Maximum number of recordings in megabytes. Once exceed, remove the oldest recordings." + }, + "protocols": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer" + }, + "description": "This is an array: 1 = Terminal, 2 = Desktop, 5 = Files, 100 = Intel AMT WSMAN, 101 = Intel AMT Redirection, 200 = Messenger" + } }, - "required": [ "protocols" ] + "required": [ + "protocols" + ] + }, + "showPasswordLogin": { + "type": "boolean", + "default": true, + "description": "When set to false, hides the username and password prompt on login screen." }, - "showPasswordLogin": { "type": "boolean", "default": true, "description": "When set to false, hides the username and password prompt on login screen." }, "sendgrid": { - "title" : "SendGrid.com Email server", + "title": "SendGrid.com Email server", "description": "Connects MeshCentral to the SendGrid email server, allows MeshCentral to send email messages for 2FA or user notification.", "type": "object", "properties": { - "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "apikey": { "type": "string", "description": "The SendGrid API key." }, - "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." } + "from": { + "type": "string", + "format": "email", + "description": "Email address used in the messages from field." + }, + "apikey": { + "type": "string", + "description": "The SendGrid API key." + }, + "verifyemail": { + "type": "boolean", + "default": true, + "description": "When set to false, the email format and DNS MX record are not checked." + }, + "emailDelaySeconds": { + "type": "integer", + "default": 300, + "description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email." + } }, - "required": [ "from", "apikey" ] + "required": [ + "from", + "apikey" + ] }, "smtp": { - "title" : "SMTP email server", + "title": "SMTP email server", "description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.", "type": "object", "properties": { "name": { "type": "string", "format": "hostname", - "description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays." + "description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays. This can also be set to \"console\" for console output debugging." }, "host": { "type": "string", @@ -1074,230 +2905,1021 @@ "type": "integer", "minimum": 1, "maximum": 65535, - "description": "SMTP server port number." + "default": 587, + "description": "SMTP server port number. This defaults to 587 if \"tls\" is false or 465 if \"tls\" is true)" }, "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "tls": { "type": "boolean" }, + "user": { + "type": "string", + "description": "SMTP username." + }, + "pass": { + "type": "string", + "description": "SMTP password." + }, + "tls": { + "type": "boolean", + "default": false, + "description": "Set SMTP to use TLS on connections, the default is false" + }, "auth": { "type": "object", + "description": "This is used for OAuth2 authentication", "properties": { - "clientId": { "type": "string" }, - "clientSecret": { "type": "string" }, - "refreshToken": { "type": "string" } + "clientId": { + "type": "string" + }, + "clientSecret": { + "type": "string" + }, + "refreshToken": { + "type": "string" + }, + "type": { + "type": "string", + "default": "login", + "description": "Setting this indicates the authetication type, 'login' as default or 'oauth2'" + } }, - "required": [ "clientId", "clientSecret", "refreshToken" ] + "required": [ + "clientId", + "clientSecret", + "refreshToken" + ] + }, + "tlscertcheck": { + "type": "boolean" + }, + "tlsstrict": { + "type": "boolean" }, - "tlscertcheck": { "type": "boolean" }, - "tlsstrict": { "type": "boolean" }, "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." + }, + "emailDelaySeconds": { + "type": "integer", + "default": 300, + "description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email." } }, - "required": [ "from" ] + "required": [ + "host", + "port", + "from", + "tls" + ] }, "sendmail": { - "title" : "Send email using the sendmail command", + "title": "Send email using the sendmail command", "description": "Makes MeshCentral send emails using the Unix sendmail command. Allows MeshCentral to send email messages for 2FA or user notification.", "type": "object", "properties": { - "newline": { "type": "string", "default": "unix", "description": "Possible values are unix or windows" }, - "path": { "type": "string", "default": "sendmail", "description": "Path to the sendmail command" }, - "args": { "type": "array", "items": { "type": "string" }, "default": null, "description": "Array or arguments to pass to sendmail" } + "newline": { + "type": "string", + "default": "unix", + "description": "Possible values are unix or windows" + }, + "path": { + "type": "string", + "default": "sendmail", + "description": "Path to the sendmail command" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "default": null, + "description": "Array or arguments to pass to sendmail" + }, + "emailDelaySeconds": { + "type": "integer", + "default": 300, + "description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email." + } } }, "authStrategies": { "type": "object", - "additionalProperties": false, "properties": { "twitter": { "type": "object", - "additionalProperties": false, "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} + "callbackurl": { + "type": "string", + "format": "uri" + }, + "newAccounts": { + "type": "boolean", + "default": false + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "clientid": { + "type": "string" + }, + "clientsecret": { + "type": "string" + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Then set, the user will be redirected to this URL when hitting the logout link." + } }, - "required": [ "clientid", "clientsecret" ] + "required": [ + "clientid", + "clientsecret" + ] }, "google": { "type": "object", "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} + "callbackurl": { + "type": "string", + "format": "uri" + }, + "newAccounts": { + "type": "boolean", + "default": false + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "clientid": { + "type": "string" + }, + "clientsecret": { + "type": "string" + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Then set, the user will be redirected to this URL when hitting the logout link." + } }, - "required": [ "clientid", "clientsecret" ] + "required": [ + "clientid", + "clientsecret" + ] }, "github": { "type": "object", "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} + "callbackurl": { + "type": "string", + "format": "uri" + }, + "newAccounts": { + "type": "boolean", + "default": false + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "clientid": { + "type": "string" + }, + "clientsecret": { + "type": "string" + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Then set, the user will be redirected to this URL when hitting the logout link." + } }, - "required": [ "clientid", "clientsecret" ] - }, - "reddit": { - "type": "object", - "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} - }, - "required": [ "clientid", "clientsecret" ] + "required": [ + "clientid", + "clientsecret" + ] }, "azure": { "type": "object", "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "tenantid": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} + "callbackurl": { + "type": "string", + "format": "uri" + }, + "newAccounts": { + "type": "boolean", + "default": false + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "clientid": { + "type": "string" + }, + "clientsecret": { + "type": "string" + }, + "tenantid": { + "type": "string" + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Then set, the user will be redirected to this URL when hitting the logout link." + } }, - "required": [ "clientid", "clientsecret", "tenantid" ] + "required": [ + "clientid", + "clientsecret", + "tenantid" + ] }, "jumpcloud": { "type": "object", "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "entityid": { "type": "string" }, - "idpurl": { "type": "string", "format": "uri" }, - "cert": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} + "callbackurl": { + "type": "string", + "format": "uri" + }, + "newAccounts": { + "type": "boolean", + "default": false + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "entityid": { + "type": "string" + }, + "idpurl": { + "type": "string", + "format": "uri" + }, + "cert": { + "type": "string" + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Then set, the user will be redirected to this URL when hitting the logout link." + } }, - "required": [ "entityid", "idpurl", "cert" ] + "required": [ + "entityid", + "idpurl", + "cert" + ] }, "saml": { "type": "object", "properties": { - "callbackurl": { "type": "string", "format": "uri" }, - "disableRequestedAuthnContext": { "type": "boolean" }, - "newAccounts": { "type": "boolean", "default": false }, - "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "newAccountsRights": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, - "entityid": { "type": "string" }, - "idpurl": { "type": "string", "format": "uri" }, - "cert": { "type": "string" }, - "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} + "callbackurl": { + "type": "string", + "format": "uri" + }, + "disableRequestedAuthnContext": { + "type": "boolean" + }, + "newAccounts": { + "type": "boolean", + "default": false + }, + "newAccountsUserGroups": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "newAccountsRights": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "entityid": { + "type": "string" + }, + "idpurl": { + "type": "string", + "format": "uri" + }, + "cert": { + "type": "string" + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Then set, the user will be redirected to this URL when hitting the logout link." + } }, - "required": [ "entityid", "idpurl", "cert" ] + "required": [ + "entityid", + "idpurl", + "cert" + ] }, "oidc": { "type": "object", + "description": "Enables the use of OpenID Connect SSO", + "anyOf": [ + { + "required": [ + "client" + ] + }, + { + "required": [ + "client", + "custom" + ] + }, + { + "required": [ + "client", + "issuer" + ] + }, + { + "required": [ + "clientid", + "clientsecret", + "issuer" + ] + } + ], "properties": { - "authorizationURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the authorization URL. (If set tokenURL and userInfoURL need set also)" }, - "callbackURL": { "type": "string", "format": "uri", "description": "Required, this is the URL that your SSO provider sends auth approval to." }, - "clientid": { "type": "string" }, - "clientsecret": { "type": "string" }, - "issuer": { "type": "string", "format": "uri", "description": "Full URL of SSO portal" }, - "tokenURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the token URL. (If set authorizationURL and userInfoURL need set also)" }, - "userInfoURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the user info URL. (If set authorizationURL and tokenURL need set also)" }, - "logouturl": { "type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link." }, - "newAccounts": { "type": "boolean", "default": true }, - "groups": { + "newAccounts": { + "type": "boolean", + "description": "Enable the creation of new accounts based upon Idp Authorization", + "default": true + }, + "newAccountsUserGroups": { + "type": [ + "string", + "array" + ], + "description": "Add all new users to these static MeshCentral user groups. Use this if the new groups section does not work with your preset.", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "newAccountsRights": { + "type": [ + "array", + "string" + ], + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "clientid": { + "type": "string", + "depreciated": true, + "description": "REPLACED WITH 'client.client_id'" + }, + "clientsecret": { + "type": "string", + "description": "REPLACED WITH 'client.client_secret'" + }, + "authorizationURL": { + "type": "string", + "format": "uri", + "depreciated": true, + "description": "REPLACED WITH 'issuer.authorization_endpoint'" + }, + "tokenURL": { + "type": "string", + "format": "uri", + "depreciated": true, + "description": "REPLACED WITH 'issuer.token_endpoint': If set, this will be used as the token URL." + }, + "userInfoURL": { + "type": "string", + "format": "uri", + "depreciated": true, + "description": "REPLACED WITH 'issuer.userinfo_endpoint': If set, this will be used as the user info URL." + }, + "scope": { + "type": [ + "string", + "array" + ], + "depreciated": true, + "description": "REPLACED WITH 'custom.scope': A list of scopes to request from the issuer." + }, + "callbackURL": { + "type": "string", + "format": "uri", + "depreciated": true, + "description": "REPLACED WITH 'client.redirect_uri': The URI your IdP sends you back to after successful authorization. This must match what is listed with your IdP." + }, + "logouturl": { + "type": "string", + "format": "uri", + "description": "Overrides defaults ( [issuer.end_session_endpoint]?post_logout_redirect_uri=[post_logout_redirect_uri] OR [issuer.end_session_endpoint] )" + }, + "client": { "type": "object", + "description": "OIDC Client Options", "properties": { - "required": { "type": [ "string", "array" ], "description": "When set, the user must be part of one of the OIDC user groups to login to MeshCentral." }, - "siteadmin": { "type": [ "string", "array" ], "description": "When set, users part of these groups will be promoted with site administrator in MeshCentral, users that are not part of these groups will be demoted." }, - "sync": { - "type": [ "boolean", "object" ], - "description": "Allows some or all ODIC user groups to be mirrored within MeshCentral as user groups.", + "client_id": { + "type": "string", + "description": "REQUIRED: The client ID provided by your Identity Provider (IdP)" + }, + "client_secret": { + "type": "string", + "description": "REQUIRED: The client secret provided by your Identity Provider (IdP)" + }, + "id_token_signed_response_alg": { + "type": "string", + "default": "RS256", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "id_token_encrypted_response_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "id_token_encrypted_response_enc": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "userinfo_signed_response_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "userinfo_encrypted_response_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "userinfo_encrypted_response_enc": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "redirect_uri": { + "type": "string", + "format": "uri", + "description": "URI your IdP sends you after successful authorization. This must match what is listed with your IdP. (Default is https://[currentHost][currentPath]/auth-oidc-callback)" + }, + "response_types": { + "type": [ + "string", + "array" + ], + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details", + "default": [ + "code" + ] + }, + "post_logout_redirect_uri": { + "type": "string", + "format": "uri", + "description": "URI for your IdP to send you after logging out of IdP via MeshCentral. (Default is https:[currentHost][currentPath]/login)" + }, + "default_max_age": { + "type": "number", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "require_auth_time": { + "type": "boolean", + "default": false, + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "request_object_signing_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "request_object_encryption_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "request_object_encryption_enc": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "token_endpoint_auth_method": { + "type": "string", + "default": "client_secret_basic", + "enum": [ + "none", + "client_secret_basic", + "client_secret_post", + "client_secret_jwt", + "private_key_jwt" + ], + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "introspection_endpoint_auth_method": { + "type": "string", + "default": "client_secret_basic", + "enum": [ + "none", + "client_secret_basic", + "client_secret_post", + "client_secret_jwt", + "private_key_jwt" + ], + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "revocation_endpoint_auth_method": { + "type": "string", + "default": "client_secret_basic", + "enum": [ + "none", + "client_secret_basic", + "client_secret_post", + "client_secret_jwt", + "private_key_jwt" + ], + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "token_endpoint_auth_signing_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "introspection_endpoint_auth_signing_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "revocation_endpoint_auth_signing_alg": { + "type": "string", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + }, + "tls_client_certificate_bound_access_tokens": { + "type": "boolean", + "description": "ADVANCED CONFIG: Check node-openid-client on GitHub for details" + } + }, + "required": [ + "client_id", + "client_secret" + ] + }, + "issuer": { + "type": [ + "string", + "object" + ], + "format": "uri", + "description": "Issuer options. Requires issuer URI (issuer.issuer) to discover missing information unless using preset", + "properties": { + "issuer": { + "type": "string", + "format": "uri", + "description": "URI of the issuer." + }, + "authorization_endpoint": { + "type": "string", + "format": "uri" + }, + "token_endpoint": { + "type": "string", + "format": "uri" + }, + "jwks_uri": { + "type": "string", + "format": "uri" + }, + "userinfo_endpoint": { + "type": "string", + "format": "uri" + }, + "revocation_endpoint": { + "type": "string", + "format": "uri" + }, + "introspection_endpoint": { + "type": "string", + "format": "uri" + }, + "end_session_endpoint": { + "type": "string", + "format": "uri", + "description": "URI to direct users to when logging out of MeshCentral. (Attempts to autodetect, defaults to '[issuer.issuer]/logout')" + }, + "registration_endpoint": { + "type": "string", + "format": "uri" + }, + "token_endpoint_auth_methods_supported": { + "type": "string" + }, + "token_endpoint_auth_signing_alg_values_supported": { + "type": "string" + }, + "introspection_endpoint_auth_methods_supported": { + "type": "string" + }, + "introspection_endpoint_auth_signing_alg_values_supported": { + "type": "string" + }, + "revocation_endpoint_auth_methods_supported": { + "type": "string" + }, + "revocation_endpoint_auth_signing_alg_values_supported": { + "type": "string" + }, + "request_object_signing_alg_values_supported": { + "type": "string" + }, + "mtls_endpoint_aliases": { + "type": "object", "properties": { - "enabled": { "type": "boolean", "default": false }, - "filter": { "type": [ "string", "array" ], "description": "When set, limits what OIDC groups are mirrored into MeshCentral user groups." } + "token_endpoint": { + "type": "string", + "format": "uri" + }, + "userinfo_endpoint": { + "type": "string", + "format": "uri" + }, + "revocation_endpoint": { + "type": "string", + "format": "uri" + }, + "introspection_endpoint": { + "type": "string", + "format": "uri" + } } } } + }, + "custom": { + "type": "object", + "properties": { + "scope": { + "type": [ + "string", + "array" + ], + "description": "A list of scopes to request from the issuer.", + "default": "openid profile email", + "examples": [ + "openid", + [ + "openid", + "profile" + ], + "openid profile email", + "openid profile email groups" + ] + }, + "claims": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "uuid": { + "type": "string" + } + } + }, + "preset": { + "type": "string", + "enum": [ + "azure", + "google" + ] + }, + "tenant_id": { + "type": "string", + "description": "REQUIRED FOR AZURE PRESET: Tenantid for Azure" + }, + "customer_id": { + "type": "string", + "description": "REQUIRED IF USING GROUPS: Customer ID from Google Workspace Admin Console (https://admin.google.com/ac/accountsettings/profile)" + } + } + }, + "groups": { + "type": "object", + "properties": { + "recursive": { + "type": "boolean", + "default": false, + "description": "When true, the group memberships will be scanned recursively." + }, + "required": { + "type": [ + "array" + ], + "description": "Access is only granted to users who are a member of at least one of the listed required groups." + }, + "siteadmin": { + "type": [ + "array" + ], + "description": "Full site admin priviledges will be granted to users who are a member of at least one of the listed admin groups." + }, + "revokeAdmin": { + "type": "boolean", + "description": "If true, admin privileges will be revoked from users who are NOT a member of at least one of the listed admin groups." + }, + "sync": { + "type": [ + "boolean", + "object" + ], + "default": false, + "description": "If true, all groups found during user login are mirrored into MeshCentral user groups.", + "properties": { + "filter": { + "type": [ + "array" + ], + "description": "Only groups listed here are mirrored into MeshCentral user groups." + } + } + }, + "scope": { + "type": "string", + "default": "groups", + "description": "Custom scope to use." + }, + "claim": { + "type": "string", + "default": "groups", + "description": "Custom claim to use." + } + } } - }, - "required": [ "issuer", "clientid", "clientsecret", "callbackURL" ] + } } } + }, + "showLanguageSelect": { + "type": "string", + "default": null, + "description": "Show Language Selector on Login Page, \"top\" inside Login Box or \"bottom\" at Bottom of Page", + "enum": [ + null, + "top", + "bottom" + ] } } } }, "letsEncrypt": { - "title" : "Built-in Let's Encrypt support", + "title": "Built-in Let's Encrypt support", "description": "If your server has a proper DNS name and it public facing on the Internet with a public facing HTTP server on port 80, you can get a free TLS certificate.", "type": "object", - "additionalProperties": false, "properties": { - "email": { "type": "string", "format": "email", "description": "Email address of the administrator of this server. Make sure this is a valid email address otherwise the certificate request will fail." }, - "names": { "type": "string" }, - "skipChallengeVerification": { "type": "boolean", "default": false, "description": "By default, MeshCentral will perform a self-test to make sure HTTP port 80 can respond correctly before making a request to Let's Encrypt. In some cases, this self-test can't work and must be skipped." }, - "production": { "type": "boolean", "default": false, "description": "By default a test certificate will be obtained from Let's Encrypt. Always start by getting a test certificate and make sure that works before setting this to true and obtaining a production certificate. Making too many bad requests for a production certificate will get you banned for a long period of time." } + "email": { + "type": "string", + "format": "email", + "description": "Email address of the administrator of this server. Make sure this is a valid email address otherwise the certificate request will fail." + }, + "names": { + "type": "string" + }, + "skipChallengeVerification": { + "type": "boolean", + "default": false, + "description": "By default, MeshCentral will perform a self-test to make sure HTTP port 80 can respond correctly before making a request to Let's Encrypt. In some cases, this self-test can't work and must be skipped." + }, + "production": { + "type": "boolean", + "default": false, + "description": "By default a test certificate will be obtained from Let's Encrypt. Setting \"zerossl\", will ignore this setting. Always start by getting a test certificate and make sure that works before setting this to true and obtaining a production certificate. Making too many bad requests for a production certificate will get you banned for a long period of time." + }, + "nochecks": { + "type": "boolean", + "default": false, + "description": "If you choose \"true\", MeshCentral won't verify if \"email\" is valid, has a valid MX record, AND if \"names\" doesn't contain a wildcard, can be resolved by DNS A/AAAA record." + }, + "zerossl": { + "type": "object", + "description": "If this object is set, we will use ZeroSSL for SSL creation instead of Let's Encrypt", + "required": [ + "kid", + "hmacKey" + ], + "properties": { + "kid": { + "type": "string", + "description": "EAB KID", + "default": "" + }, + "hmackey": { + "type": "string", + "description": "EAB HMAC KEY", + "default": "" + } + } + } }, - "required": [ "email", "names" ] + "required": [ + "email", + "names" + ] }, "peers": { - "title" : "Server peering", + "title": "Server peering", "description": "Setup peer server for load-balancing between many servers.", "type": "object", "minProperties": 1, - "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, - "additionalProperties": false, + "propertyNames": { + "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" + }, "properties": { - "serverId": { "type": "string" }, + "serverId": { + "type": "string" + }, "servers": { "type": "object", "additionalProperties": { "type": "object", - "properties": { "url": { "type": "string", "format": "uri" } }, - "required": [ "url" ] + "properties": { + "url": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "url" + ] } } }, - "required": [ "serverId", "servers" ] + "required": [ + "serverId", + "servers" + ] }, "sendgrid": { - "title" : "SendGrid.com Email server", + "title": "SendGrid.com Email server", "description": "Connects MeshCentral to the SendGrid email server, allows MeshCentral to send email messages for 2FA or user notification.", "type": "object", "properties": { - "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "apikey": { "type": "string", "description": "The SendGrid API key." }, - "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." } + "from": { + "type": "string", + "format": "email", + "description": "Email address used in the messages from field." + }, + "apikey": { + "type": "string", + "description": "The SendGrid API key." + }, + "verifyemail": { + "type": "boolean", + "default": true, + "description": "When set to false, the email format and DNS MX record are not checked." + } }, - "required": [ "from", "apikey" ] + "required": [ + "from", + "apikey" + ] }, "smtp": { - "title" : "SMTP email server", + "title": "SMTP email server", "description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.", "type": "object", "properties": { - "host": { "type": "string", "format": "hostname" }, - "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, - "from": { "type": "string", "format": "email", "description": "Email address used in the messages from field." }, - "tls": { "type": "boolean" }, - "tlscertcheck": { "type": "boolean" }, - "tlsstrict": { "type": "boolean" }, - "verifyemail": { "type": "boolean", "default": true, "description": "When set to false, the email format and DNS MX record are not checked." } + "name": { + "type": "string", + "format": "hostname", + "description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays. This can also be set to \"console\" for console output debugging." + }, + "host": { + "type": "string", + "format": "hostname", + "description": "Hostname of the SMTP server." + }, + "port": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "default": 587, + "description": "SMTP server port number. This defaults to 587 if \"tls\" is false or 465 if \"tls\" is true)" + }, + "from": { + "type": "string", + "format": "email", + "description": "Email address used in the messages from field." + }, + "user": { + "type": "string", + "description": "SMTP username." + }, + "pass": { + "type": "string", + "description": "SMTP password." + }, + "tls": { + "type": "boolean", + "default": false, + "description": "Set SMTP to use TLS on connections, the default is false" + }, + "auth": { + "type": "object", + "description": "This is used for OAuth2 authentication", + "properties": { + "clientId": { + "type": "string" + }, + "clientSecret": { + "type": "string" + }, + "refreshToken": { + "type": "string" + }, + "type": { + "type": "string", + "default": "login", + "description": "Setting this indicates the authetication type, 'login' as default or 'oauth2'" + } + }, + "required": [ + "clientId", + "clientSecret", + "refreshToken" + ] + }, + "tlscertcheck": { + "type": "boolean" + }, + "tlsstrict": { + "type": "boolean" + }, + "verifyemail": { + "type": "boolean", + "default": true, + "description": "When set to false, the email format and DNS MX record are not checked." + }, + "emailDelaySeconds": { + "type": "integer", + "default": 300, + "description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email." + } }, - "required": [ "host", "port", "from", "tls" ] + "required": [ + "host", + "port", + "from", + "tls" + ] + }, + "sendmail": { + "title": "Send email using the sendmail command", + "description": "Makes MeshCentral send emails using the Unix sendmail command. Allows MeshCentral to send email messages for 2FA or user notification.", + "type": "object", + "properties": { + "newline": { + "type": "string", + "default": "unix", + "description": "Possible values are unix or windows" + }, + "path": { + "type": "string", + "default": "sendmail", + "description": "Path to the sendmail command" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "default": null, + "description": "Array or arguments to pass to sendmail" + }, + "emailDelaySeconds": { + "type": "integer", + "default": 300, + "description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email." + } + } }, "sms": { "title": "SMS provider", @@ -1308,57 +3930,97 @@ "properties": { "provider": { "type": "string", - "enum": [ "twilio" ] + "enum": [ + "twilio" + ] }, - "sid": { "type": "string" }, - "auth": { "type": "string" }, - "from": { "type": "string" } + "sid": { + "type": "string" + }, + "auth": { + "type": "string" + }, + "from": { + "type": "string" + } }, - "required": [ "provider", "sid", "auth", "from" ] + "required": [ + "provider", + "sid", + "auth", + "from" + ] }, { "type": "object", "properties": { "provider": { "type": "string", - "enum": [ "plivo" ] + "enum": [ + "plivo" + ] }, - "id": { "type": "string" }, - "token": { "type": "string" }, - "from": { "type": "string" } + "id": { + "type": "string" + }, + "token": { + "type": "string" + }, + "from": { + "type": "string" + } }, - "required": [ "provider", "id", "token", "from" ] + "required": [ + "provider", + "id", + "token", + "from" + ] }, { "type": "object", "properties": { "provider": { "type": "string", - "enum": [ "telnyx" ] + "enum": [ + "telnyx" + ] }, - "apikey": { "type": "string" }, - "from": { "type": "string" } + "apikey": { + "type": "string" + }, + "from": { + "type": "string" + } }, - "required": [ "provider", "apikey", "from" ] + "required": [ + "provider", + "apikey", + "from" + ] }, { "type": "object", "properties": { "provider": { "type": "string", - "enum": [ "url" ] + "enum": [ + "url" + ] }, "url": { "type": "string", "description": "A http or https URL with {{phone}} and {{message}} in the string. These will be replaced with the URL encoded target phone number and message." } }, - "required": [ "url" ] + "required": [ + "url" + ] } ] }, "messaging": { - "title" : "Messaging server", + "title": "Messaging server", "description": "This section allow MeshCentral to send messages over user messaging networks like Telegram", "type": "object", "properties": { @@ -1366,69 +4028,134 @@ "type": "object", "description": "Configure Telegram messaging system", "properties": { - "apiid": { "type": "number" }, - "apihash": { "type": "string" }, - "session": { "type": "string" } + "apiid": { + "type": "number" + }, + "apihash": { + "type": "string" + }, + "session": { + "type": "string" + }, + "useWSS": { + "type": "boolean", + "description": "Whether to try to connect over Wss (or 443 port) or not" + }, + "connectionRetries": { + "type": "number", + "description": "How many times the reconnection should retry, either on the initial connection or when Telegram disconnects us. May be set to a negative value for infinite retries, but this is not recommended. Defaults to 5" + } } }, "discord": { "type": "object", "description": "Configure Discord messaging system", "properties": { - "serverurl": { "type": "string", "format": "uri", "description": "An optional HTTP link to the discord server the user must join to get notifications." }, - "token": { "type": "string", "description": "A Discord bot token that MeshCentral will use to login to Discord." } + "serverurl": { + "type": "string", + "format": "uri", + "description": "An optional HTTP link to the discord server the user must join to get notifications." + }, + "token": { + "type": "string", + "description": "A Discord bot token that MeshCentral will use to login to Discord." + } }, - "required": [ "token" ] + "required": [ + "token" + ] }, "xmpp": { "type": "object", "description": "Configure XMPP messaging system", "properties": { - "service": { "type": "string", "description": "Host name of the XMPP server." }, + "service": { + "type": "string", + "description": "Host name of the XMPP server." + }, "credentials": { "type": "object", "description": "Login credentials for the XMPP server.", "properties": { - "username": { "type": "string" }, - "password": { "type": "string" } + "username": { + "type": "string" + }, + "password": { + "type": "string" + } } } }, - "required": [ "credentials" ] + "required": [ + "credentials" + ] }, "callmebot": { "type": "boolean", "default": false, "description": "Enabled CallMeBot integration support." }, + "slack": { + "type": "boolean", + "default": false, + "description": "Enabled Slack integration support." + }, "pushover": { "type": "object", "description": "Configure Pushover messaging system", "properties": { - "token": { "type": "string", "description": "A Pushover application token that MeshCentral will use to login." } + "token": { + "type": "string", + "description": "A Pushover application token that MeshCentral will use to login." + } }, - "required": [ "token" ] + "required": [ + "token" + ] }, "ntfy": { - "type": [ "boolean", "object" ], + "type": [ + "boolean", + "object" + ], "default": false, "properties": { - "host": { "type": "string", "description": "Host name of the ntfy server." }, - "userurl": { "type": "string", "description": "A URL given to users to help them setup this service." } + "host": { + "type": "string", + "description": "Host name of the ntfy server." + }, + "userurl": { + "type": "string", + "description": "A URL given to users to help them setup this service." + }, + "authorization": { + "type": "string", + "description": "Authorization Header to include in the request" + } }, "description": "Enabled ntfy.sh integration support." }, "zulip": { "type": "object", "properties": { - "site": { "type": "string", "format": "uri", "default": "https://api.zulip.com", "description": "URL to the Zulip server"}, - "email": { "type": "string", "description": "Bot email address to login as." }, - "api_key": { "type": "string", "description": "Bot api key." } + "site": { + "type": "string", + "format": "uri", + "default": "https://api.zulip.com", + "description": "URL to the Zulip server" + }, + "email": { + "type": "string", + "description": "Bot email address to login as." + }, + "api_key": { + "type": "string", + "description": "Bot api key." + } }, "description": "Enabled Zulip integration support." } } } - }, - "required": [ "settings", "domains" ] + } } diff --git a/meshcentral.js b/meshcentral.js index b554e3d3..a792dda5 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -86,7 +86,7 @@ function CreateMeshCentralServer(config, args) { obj.parentpath = obj.path.join(__dirname, '../..'); obj.datapath = obj.path.join(__dirname, '../../meshcentral-data'); obj.filespath = obj.path.join(__dirname, '../../meshcentral-files'); - obj.backuppath = obj.path.join(__dirname, '../../meshcentral-backup'); + obj.backuppath = obj.path.join(__dirname, '../../meshcentral-backups'); obj.recordpath = obj.path.join(__dirname, '../../meshcentral-recordings'); obj.webViewsPath = obj.path.join(__dirname, 'views'); obj.webPublicPath = obj.path.join(__dirname, 'public'); @@ -139,9 +139,23 @@ function CreateMeshCentralServer(config, args) { try { require('./pass').hash('test', function () { }, 0); } catch (ex) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not. // Check for invalid arguments - const validArguments = ['_', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'showitem', 'listuserids', 'showusergroups', 'shownodes', 'showallmeshes', 'showmeshes', 'showevents', 'showsmbios', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbfix', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log', 'dbstats', 'translate', 'createaccount', 'setuptelegram', 'resetaccount', 'pass', 'removesubdomain', 'adminaccount', 'domain', 'email', 'configfile', 'maintenancemode', 'nedbtodb', 'removetestagents', 'agentupdatetest', 'hashpassword', 'hashpass', 'indexmcrec', 'mpsdebug', 'dumpcores']; + const validArguments = ['_', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'showitem', 'listuserids', 'showusergroups', 'shownodes', 'showallmeshes', 'showmeshes', 'showevents', 'showsmbios', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbfix', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'usenodedefaulttlsciphers', 'tlsciphers', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'oldencrypt', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log', 'dbstats', 'translate', 'createaccount', 'setuptelegram', 'resetaccount', 'pass', 'removesubdomain', 'adminaccount', 'domain', 'email', 'configfile', 'maintenancemode', 'nedbtodb', 'removetestagents', 'agentupdatetest', 'hashpassword', 'hashpass', 'indexmcrec', 'mpsdebug', 'dumpcores', 'dev', 'mysql', 'mariadb', 'trustedproxy']; for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } } + const ENVVAR_PREFIX = "meshcentral_" + let envArgs = [] + for (let [envvar, envval] of Object.entries(process.env)) { + if (envvar.toLocaleLowerCase().startsWith(ENVVAR_PREFIX)) { + let argname = envvar.slice(ENVVAR_PREFIX.length).toLocaleLowerCase() + if (!!argname && !(validArguments.indexOf(argname) == -1)) { + envArgs = envArgs.concat([`--${argname}`, envval]) + } + } + } + envArgs = require('minimist')(envArgs) + obj.args = Object.assign(envArgs, obj.args) if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; } + if (obj.args.mysql == true) { console.log('Must specify: --mysql [connectionstring] \r\nExample mysql://user:password@127.0.0.1:3306/database'); return; } + if (obj.args.mariadb == true) { console.log('Must specify: --mariadb [connectionstring] \r\nExample mariadb://user:password@127.0.0.1:3306/database'); return; } for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence. if ((obj.args.help == true) || (obj.args['?'] == true)) { @@ -220,6 +234,12 @@ function CreateMeshCentralServer(config, args) { translateEngine.startEx(['', '', 'translateall', translationFile]); translateEngine.startEx(['', '', 'extractall', translationFile]); didSomething = true; + } else { + // Translate all of the default files + translateEngine.startEx(['', '', 'minifyall']); + translateEngine.startEx(['', '', 'translateall']); + translateEngine.startEx(['', '', 'extractall']); + didSomething = true; } // Check if "meshcentral-web" exists, if so, translate all pages in that folder. @@ -235,11 +255,34 @@ function CreateMeshCentralServer(config, args) { files = obj.fs.readdirSync(obj.webViewsOverridePath); for (var i in files) { var file = obj.path.join(obj.webViewsOverridePath, files[i]); - if (file.endsWith('.handlebars') || file.endsWith('-min.handlebars')) { + if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) { translateEngine.startEx(['', '', 'translate', '*', translationFile, file, '--subdir:translations']); } } } + + // Check domains and see if "meshcentral-web-DOMAIN" exists, if so, translate all pages in that folder + for (i in obj.config.domains) { + if (i == "") continue; + var path = obj.path.join(obj.datapath, '..', 'meshcentral-web-' + i, 'views'); + if (require('fs').existsSync(path)) { + didSomething = true; + var files = obj.fs.readdirSync(path); + for (var a in files) { + var file = obj.path.join(path, files[a]); + if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) { + translateEngine.startEx(['', '', 'minify', file]); + } + } + files = obj.fs.readdirSync(path); + for (var a in files) { + var file = obj.path.join(path, files[a]); + if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) { + translateEngine.startEx(['', '', 'translate', '*', translationFile, file, '--subdir:translations']); + } + } + } + } /* if (obj.webPublicOverridePath != null) { didSomething = true; @@ -254,6 +297,7 @@ function CreateMeshCentralServer(config, args) { */ if (didSomething == false) { console.log("Nothing to do."); } + console.log('Finished Translating.') process.exit(); return; } @@ -286,7 +330,7 @@ function CreateMeshCentralServer(config, args) { require('child_process').exec('which node', {}, function (error, stdout, stderr) { if ((error != null) || (stdout.indexOf('\n') == -1)) { console.log('ERROR: Unable to get node location: ' + error); process.exit(); return; } const nodePath = stdout.substring(0, stdout.indexOf('\n')); - const config = '[Unit]\nDescription=MeshCentral Server\n\n[Service]\nType=simple\nLimitNOFILE=1000000\nExecStart=' + nodePath + ' ' + __dirname + '/meshcentral\nWorkingDirectory=' + userinfo.homedir + '\nEnvironment=NODE_ENV=production\nUser=' + userinfo.username + '\nGroup=' + userinfo.username + '\nRestart=always\n# Restart service after 10 seconds if node service crashes\nRestartSec=10\n# Set port permissions capability\nAmbientCapabilities=cap_net_bind_service\n\n[Install]\nWantedBy=multi-user.target\n'; + const config = '[Unit]\nDescription=MeshCentral Server\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nType=simple\nLimitNOFILE=1000000\nExecStart=' + nodePath + ' ' + __dirname + '/meshcentral\nWorkingDirectory=' + userinfo.homedir + '\nEnvironment=NODE_ENV=production\nUser=' + userinfo.username + '\nGroup=' + userinfo.username + '\nRestart=always\n# Restart service after 10 seconds if node service crashes\nRestartSec=10\n# Set port permissions capability\nAmbientCapabilities=cap_net_bind_service\n\n[Install]\nWantedBy=multi-user.target\n'; require('child_process').exec('echo \"' + config + '\" | sudo tee ' + systemdConf, {}, function (error, stdout, stderr) { if ((error != null) && (error != '')) { console.log('ERROR: Unable to write config file: ' + error); process.exit(); return; } console.log('Enabling service...'); @@ -350,6 +394,92 @@ function CreateMeshCentralServer(config, args) { return; } } + + // FreeBSD background service handling, MUST USE SPAWN FOR SERVICE COMMANDS! + if (obj.platform == 'freebsd') { + if (obj.args.install == true) { + // Install MeshCentral in rc.d + console.log('Installing MeshCentral as background Service...'); + var systemdConf = "/usr/local/etc/rc.d/meshcentral"; + const userinfo = require('os').userInfo(); + console.log('Writing config file...'); + require('child_process').exec('which node', {}, function (error, stdout, stderr) { + if ((error != null) || (stdout.indexOf('\n') == -1)) { console.log('ERROR: Unable to get node location: ' + error); process.exit(); return; } + const nodePath = stdout.substring(0, stdout.indexOf('\n')); + const config = '#!/bin/sh\n# MeshCentral FreeBSD Service Script\n# PROVIDE: meshcentral\n# REQUIRE: NETWORKING\n# KEYWORD: shutdown\n. /etc/rc.subr\nname=meshcentral\nuser=' + userinfo.username + '\nrcvar=meshcentral_enable\n: \\${meshcentral_enable:=\\"NO\\"}\n: \\${meshcentral_args:=\\"\\"}\npidfile=/var/run/meshcentral/meshcentral.pid\ncommand=\\"/usr/sbin/daemon\\"\nmeshcentral_chdir=\\"' + obj.parentpath + '\\"\ncommand_args=\\"-r -u \\${user} -P \\${pidfile} -S -T meshcentral -m 3 ' + nodePath + ' ' + __dirname + ' \\${meshcentral_args}\\"\nload_rc_config \\$name\nrun_rc_command \\"\\$1\\"\n'; + require('child_process').exec('echo \"' + config + '\" | tee ' + systemdConf + ' && chmod +x ' + systemdConf, {}, function (error, stdout, stderr) { + if ((error != null) && (error != '')) { console.log('ERROR: Unable to write config file: ' + error); process.exit(); return; } + console.log('Enabling service...'); + require('child_process').exec('sysrc meshcentral_enable="YES"', {}, function (error, stdout, stderr) { + if ((error != null) && (error != '')) { console.log('ERROR: Unable to enable MeshCentral as a service: ' + error); process.exit(); return; } + if (stdout.length > 0) { console.log(stdout); } + console.log('Starting service...'); + const service = require('child_process').spawn('service', ['meshcentral', 'start']); + service.stdout.on('data', function (data) { console.log(data.toString()); }); + service.stderr.on('data', function (data) { console.log(data.toString()); }); + service.on('exit', function (code) { + console.log((code === 0) ? 'Done.' : 'ERROR: Unable to start MeshCentral as a service'); + process.exit(); // Must exit otherwise we just hang + }); + }); + }); + }); + return; + } else if (obj.args.uninstall == true) { + // Uninstall MeshCentral in rc.d + console.log('Uninstalling MeshCentral background service...'); + var systemdConf = "/usr/local/etc/rc.d/meshcentral"; + console.log('Stopping service...'); + const service = require('child_process').spawn('service', ['meshcentral', 'stop']); + service.stdout.on('data', function (data) { console.log(data.toString()); }); + service.stderr.on('data', function (data) { console.log(data.toString()); }); + service.on('exit', function (code) { + if (code !== 0) { console.log('ERROR: Unable to stop MeshCentral as a service'); } + console.log('Disabling service...'); + require('child_process').exec('sysrc -x meshcentral_enable', {}, function (err, stdout, stderr) { + if ((err != null) && (err != '')) { console.log('ERROR: Unable to disable MeshCentral as a service: ' + err); } + if (stdout.length > 0) { console.log(stdout); } + console.log('Removing config file...'); + require('child_process').exec('rm ' + systemdConf, {}, function (err, stdout, stderr) { + if ((err != null) && (err != '')) { console.log('ERROR: Unable to delete MeshCentral config file: ' + err); } + console.log('Done.'); + process.exit(); // Must exit otherwise we just hang + }); + }); + }); + return; + } else if (obj.args.start == true) { + // Start MeshCentral in rc.d + const service = require('child_process').spawn('service', ['meshcentral', 'start']); + service.stdout.on('data', function (data) { console.log(data.toString()); }); + service.stderr.on('data', function (data) { console.log(data.toString()); }); + service.on('exit', function (code) { + console.log((code === 0) ? 'Done.' : 'ERROR: Unable to start MeshCentral as a service: ' + error); + process.exit(); // Must exit otherwise we just hang + }); + return; + } else if (obj.args.stop == true) { + // Stop MeshCentral in rc.d + const service = require('child_process').spawn('service', ['meshcentral', 'stop']); + service.stdout.on('data', function (data) { console.log(data.toString()); }); + service.stderr.on('data', function (data) { console.log(data.toString()); }); + service.on('exit', function (code) { + console.log((code === 0) ? 'Done.' : 'ERROR: Unable to stop MeshCentral as a service: ' + error); + process.exit(); // Must exit otherwise we just hang + }); + return; + } else if (obj.args.restart == true) { + // Restart MeshCentral in rc.d + const service = require('child_process').spawn('service', ['meshcentral', 'restart']); + service.stdout.on('data', function (data) { console.log(data.toString()); }); + service.stderr.on('data', function (data) { console.log(data.toString()); }); + service.on('exit', function (code) { + console.log((code === 0) ? 'Done.' : 'ERROR: Unable to restart MeshCentral as a service: ' + error); + process.exit(); // Must exit otherwise we just hang + }); + return; + } + } // Index a recorded file if (obj.args.indexmcrec != null) { @@ -453,7 +583,11 @@ function CreateMeshCentralServer(config, args) { // Launch MeshCentral as a child server and monitor it. obj.launchChildServer = function (startArgs) { const child_process = require('child_process'); + const isInspectorAttached = (()=> { try { return require('node:inspector').url() !== undefined; } catch (_) { return false; } }).call(); + const logFromChildProcess = isInspectorAttached ? () => {} : console.log.bind(console); try { if (process.traceDeprecation === true) { startArgs.unshift('--trace-deprecation'); } } catch (ex) { } + try { if (process.traceProcessWarnings === true) { startArgs.unshift('--trace-warnings'); } } catch (ex) { } + if (startArgs[0] != "--disable-proto=delete") startArgs.unshift("--disable-proto=delete") childProcess = child_process.execFile(process.argv[0], startArgs, { maxBuffer: Infinity, cwd: obj.parentpath }, function (error, stdout, stderr) { if (childProcess.xrestart == 1) { setTimeout(function () { obj.launchChildServer(startArgs); }, 500); // This is an expected restart. @@ -470,9 +604,10 @@ function CreateMeshCentralServer(config, args) { const npmproxy = ((typeof obj.args.npmproxy == 'string') ? (' --proxy ' + obj.args.npmproxy) : ''); const env = Object.assign({}, process.env); // Shallow clone if (typeof obj.args.npmproxy == 'string') { env['HTTP_PROXY'] = env['HTTPS_PROXY'] = env['http_proxy'] = env['https_proxy'] = obj.args.npmproxy; } - const xxprocess = child_process.exec(npmpath + ' install --no-package-lock meshcentral' + version + npmproxy, { maxBuffer: Infinity, cwd: obj.parentpath, env: env }, function (error, stdout, stderr) { + // always use --save-exact - https://stackoverflow.com/a/64507176/1210734 + const xxprocess = child_process.exec(npmpath + ' install --save-exact --no-audit meshcentral' + version + npmproxy, { maxBuffer: Infinity, cwd: obj.parentpath, env: env }, function (error, stdout, stderr) { if ((error != null) && (error != '')) { console.log('Update failed: ' + error); } - }); + }); xxprocess.data = ''; xxprocess.stdout.on('data', function (data) { xxprocess.data += data; }); xxprocess.stderr.on('data', function (data) { xxprocess.data += data; }); @@ -524,12 +659,12 @@ function CreateMeshCentralServer(config, args) { else if (data.indexOf('Starting self upgrade to: ') >= 0) { obj.args.specificupdate = data.substring(26).split('\r')[0].split('\n')[0]; childProcess.xrestart = 3; } var datastr = data; while (datastr.endsWith('\r') || datastr.endsWith('\n')) { datastr = datastr.substring(0, datastr.length - 1); } - console.log(datastr); + logFromChildProcess(datastr); }); childProcess.stderr.on('data', function (data) { var datastr = data; while (datastr.endsWith('\r') || datastr.endsWith('\n')) { datastr = datastr.substring(0, datastr.length - 1); } - console.log('ERR: ' + datastr); + logFromChildProcess('ERR: ' + datastr); if (data.startsWith('le.challenges[tls-sni-01].loopback')) { return; } // Ignore this error output from GreenLock if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.logError(data); @@ -616,7 +751,7 @@ function CreateMeshCentralServer(config, args) { obj.performServerUpdate = function (version) { if (obj.serverSelfWriteAllowed != true) return false; if ((version == null) || (version == '') || (typeof version != 'string')) { console.log('Starting self upgrade...'); } else { console.log('Starting self upgrade to: ' + version); } - process.exit(200); + process.exit(200); return true; }; @@ -646,7 +781,7 @@ function CreateMeshCentralServer(config, args) { // Get new instance of the client const vault = require("node-vault")({ endpoint: obj.args.vault.endpoint, token: obj.args.vault.token }); vault.unseal({ key: obj.args.vault.unsealkey }) - .then(function() { + .then(function () { if (obj.args.vaultdeleteconfigfiles) { vault.delete('secret/data/' + obj.args.vault.name) .then(function (r) { console.log('Done.'); process.exit(); }) @@ -703,7 +838,7 @@ function CreateMeshCentralServer(config, args) { obj.args = args = config2.settings; // Lower case all keys in the config file - obj.common.objKeysToLower(config2, ['ldapoptions', 'defaultuserwebstate', 'forceduserwebstate', 'httpheaders']); + obj.common.objKeysToLower(config2, ['ldapoptions', 'defaultuserwebstate', 'forceduserwebstate', 'httpheaders', 'telegram/proxy']); // Grad some of the values from the original config.json file if present. if ((config.settings.vault != null) && (config2.settings != null)) { config2.settings.vault = config.settings.vault; } @@ -762,7 +897,7 @@ function CreateMeshCentralServer(config, args) { } // Check top level configuration for any unrecognized values - if (config) { for (var i in config) { if ((typeof i == 'string') && (i.length > 0) && (i[0] != '_') && (['settings', 'domaindefaults', 'domains', 'configfiles', 'smtp', 'letsencrypt', 'peers', 'sms', 'messaging', 'sendgrid', 'sendmail', 'firebase', 'firebaserelay', '$schema'].indexOf(i) == -1)) { addServerWarning('Unrecognized configuration option \"' + i + '\".', 3, [ i ]); } } } + if (config) { for (var i in config) { if ((typeof i == 'string') && (i.length > 0) && (i[0] != '_') && (['settings', 'domaindefaults', 'domains', 'configfiles', 'smtp', 'letsencrypt', 'peers', 'sms', 'messaging', 'sendgrid', 'sendmail', 'firebase', 'firebaserelay', '$schema'].indexOf(i) == -1)) { addServerWarning('Unrecognized configuration option \"' + i + '\".', 3, [i]); } } } // Read IP lists from files if applicable config.settings.userallowedip = obj.args.userallowedip = readIpListFromFile(obj.args.userallowedip); @@ -772,11 +907,11 @@ function CreateMeshCentralServer(config, args) { config.settings.swarmallowedip = obj.args.swarmallowedip = readIpListFromFile(obj.args.swarmallowedip); // Check IP lists and ranges - if (typeof obj.args.userallowedip == 'string') { if (obj.args.userallowedip == '') { config.settings.userallowedip = obj.args.userallowedip = null; } else { config.settings.userallowedip = obj.args.userallowedip = obj.args.userallowedip.split(','); } } - if (typeof obj.args.userblockedip == 'string') { if (obj.args.userblockedip == '') { config.settings.userblockedip = obj.args.userblockedip = null; } else { config.settings.userblockedip = obj.args.userblockedip = obj.args.userblockedip.split(','); } } - if (typeof obj.args.agentallowedip == 'string') { if (obj.args.agentallowedip == '') { config.settings.agentallowedip = obj.args.agentallowedip = null; } else { config.settings.agentallowedip = obj.args.agentallowedip = obj.args.agentallowedip.split(','); } } - if (typeof obj.args.agentblockedip == 'string') { if (obj.args.agentblockedip == '') { config.settings.agentblockedip = obj.args.agentblockedip = null; } else { config.settings.agentblockedip = obj.args.agentblockedip = obj.args.agentblockedip.split(','); } } - if (typeof obj.args.swarmallowedip == 'string') { if (obj.args.swarmallowedip == '') { obj.args.swarmallowedip = null; } else { obj.args.swarmallowedip = obj.args.swarmallowedip.split(','); } } + if (typeof obj.args.userallowedip == 'string') { if (obj.args.userallowedip == '') { config.settings.userallowedip = obj.args.userallowedip = null; } else { config.settings.userallowedip = obj.args.userallowedip = obj.args.userallowedip.split(' ').join('').split(','); } } + if (typeof obj.args.userblockedip == 'string') { if (obj.args.userblockedip == '') { config.settings.userblockedip = obj.args.userblockedip = null; } else { config.settings.userblockedip = obj.args.userblockedip = obj.args.userblockedip.split(' ').join('').split(','); } } + if (typeof obj.args.agentallowedip == 'string') { if (obj.args.agentallowedip == '') { config.settings.agentallowedip = obj.args.agentallowedip = null; } else { config.settings.agentallowedip = obj.args.agentallowedip = obj.args.agentallowedip.split(' ').join('').split(','); } } + if (typeof obj.args.agentblockedip == 'string') { if (obj.args.agentblockedip == '') { config.settings.agentblockedip = obj.args.agentblockedip = null; } else { config.settings.agentblockedip = obj.args.agentblockedip = obj.args.agentblockedip.split(' ').join('').split(','); } } + if (typeof obj.args.swarmallowedip == 'string') { if (obj.args.swarmallowedip == '') { obj.args.swarmallowedip = null; } else { obj.args.swarmallowedip = obj.args.swarmallowedip.split(' ').join('').split(','); } } if ((typeof obj.args.agentupdateblocksize == 'number') && (obj.args.agentupdateblocksize >= 1024) && (obj.args.agentupdateblocksize <= 65531)) { obj.agentUpdateBlockSize = obj.args.agentupdateblocksize; } if (typeof obj.args.trustedproxy == 'string') { obj.args.trustedproxy = obj.args.trustedproxy.split(' ').join('').split(','); } if (typeof obj.args.tlsoffload == 'string') { obj.args.tlsoffload = obj.args.tlsoffload.split(' ').join('').split(','); } @@ -854,7 +989,7 @@ function CreateMeshCentralServer(config, args) { return; } if (obj.args.resetaccount) { // Unlock a user account, set a new password and remove 2FA - if ((typeof obj.args.resetaccount != 'string') || ((obj.args.pass == null) && (obj.args.hashpass == null)) || (obj.args.pass == '') || (obj.args.hashpass == '') || (obj.args.resetaccount.indexOf(' ') >= 0)) { console.log("Usage: --resetaccount [userid] --domain (domain) --pass [password]."); process.exit(); return; } + if ((typeof obj.args.resetaccount != 'string') || (obj.args.resetaccount.indexOf(' ') >= 0)) { console.log("Usage: --resetaccount [userid] --domain (domain) --pass [password]."); process.exit(); return; } var userid = 'user/' + (obj.args.domain ? obj.args.domain : '') + '/' + obj.args.resetaccount.toLowerCase(); if (obj.args.resetaccount.startsWith('user/')) { userid = obj.args.resetaccount; } if (userid.split('/').length != 3) { console.log("Invalid userid."); process.exit(); return; } @@ -863,16 +998,30 @@ function CreateMeshCentralServer(config, args) { if ((docs == null) || (docs.length == 0)) { console.log("Unknown userid, usage: --resetaccount [userid] --domain (domain) --pass [password]."); process.exit(); return; } const user = docs[0]; if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { user.siteadmin -= 32; } // Unlock the account. delete user.phone; delete user.otpekey; delete user.otpsecret; delete user.otpkeys; delete user.otphkeys; delete user.otpdev; delete user.otpsms; delete user.otpmsg; // Disable 2FA - if (obj.args.hashpass) { - // Reset an account using a pre-hashed password. Use --hashpassword to pre-hash a password. - var hashpasssplit = obj.args.hashpass.split(','); - if (hashpasssplit.length != 2) { console.log("Invalid hashed password."); process.exit(); return; } - user.salt = hashpasssplit[0]; - user.hash = hashpasssplit[1]; - obj.db.Set(user, function () { console.log("Done. This command will only work if MeshCentral is stopped."); process.exit(); return; }); + delete user.msghandle; // Disable users 2fa messaging too + var config = getConfig(false); + if (config.domains[user.domain].auth || config.domains[user.domain].authstrategies) { + console.log('This users domain has external authentication methods enabled so the password will not be changed if you set one') + obj.db.Set(user, function () { console.log("Done."); process.exit(); return; }); } else { - // Hash the password and reset the account. - require('./pass').hash(String(obj.args.pass), user.salt, function (err, hash, tag) { if (err) { console.log("Unable to reset password: " + err); process.exit(); return; } user.hash = hash; obj.db.Set(user, function () { console.log("Done."); process.exit(); return; }); }, 0); + if (obj.args.hashpass && (typeof obj.args.hashpass == 'string')) { + // Reset an account using a pre-hashed password. Use --hashpassword to pre-hash a password. + var hashpasssplit = obj.args.hashpass.split(','); + if (hashpasssplit.length != 2) { console.log("Invalid hashed password."); process.exit(); return; } + user.salt = hashpasssplit[0]; + user.hash = hashpasssplit[1]; + obj.db.Set(user, function () { console.log("Done. This command will only work if MeshCentral is stopped."); process.exit(); return; }); + } else if (obj.args.pass && (typeof obj.args.pass == 'string')) { + // Hash the password and reset the account. + require('./pass').hash(String(obj.args.pass), user.salt, function (err, hash, tag) { + if (err) { console.log("Unable to reset password: " + err); process.exit(); return; } + user.hash = hash; + obj.db.Set(user, function () { console.log("Done."); process.exit(); return; }); + }, 0); + } else { + console.log('Not setting a users password'); + obj.db.Set(user, function () { console.log("Done."); process.exit(); return; }); + } } }); return; @@ -969,7 +1118,27 @@ function CreateMeshCentralServer(config, args) { // Show a list of all configuration files in the database if (obj.args.dblistconfigfiles) { - obj.db.GetAllType('cfile', function (err, docs) { if (err == null) { if (docs.length == 0) { console.log("No files found."); } else { for (var i in docs) { console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' bytes.'); } } } else { console.log('Unable to read from database.'); } process.exit(); }); return; + obj.db.GetAllType('cfile', function (err, docs) { + if (err == null) { + if (docs.length == 0) { + console.log("No files found."); + } else { + for (var i in docs) { + if (typeof obj.args.dblistconfigfiles == 'string') { + const data = obj.db.decryptData(obj.args.dblistconfigfiles, docs[i].data); + if (data == null) { + console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' encrypted bytes - Unable to decrypt.'); + } else { + console.log(docs[i]._id.split('/')[1] + ', ' + data.length + ' bytes, decoded correctly.'); + } + } else { + console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' encrypted bytes.'); + } + } + } + } else { console.log('Unable to read from database.'); } process.exit(); + }); + return; } // Display the content of a configuration file in the database @@ -1014,7 +1183,11 @@ function CreateMeshCentralServer(config, args) { const path = obj.path.join(obj.args.dbpushconfigfiles, files[i]), binary = Buffer.from(obj.fs.readFileSync(path, { encoding: 'binary' }), 'binary'); console.log('Pushing ' + file + ', ' + binary.length + ' bytes.'); lockCount++; - obj.db.setConfigFile(file, obj.db.encryptData(obj.args.configkey, binary), function () { if ((--lockCount) == 0) { console.log('Done.'); process.exit(); } }); + if (obj.args.oldencrypt) { + obj.db.setConfigFile(file, obj.db.oldEncryptData(obj.args.configkey, binary), function () { if ((--lockCount) == 0) { console.log('Done.'); process.exit(); } }); + } else { + obj.db.setConfigFile(file, obj.db.encryptData(obj.args.configkey, binary), function () { if ((--lockCount) == 0) { console.log('Done.'); process.exit(); } }); + } } } if (--lockCount == 0) { process.exit(); } @@ -1091,7 +1264,7 @@ function CreateMeshCentralServer(config, args) { for (var j in doc) { if (j.indexOf('.') >= 0) { console.log("Invalid field name (" + j + ") in document: " + json[i]); return; } } //if ((json[i].type == 'ifinfo') && (json[i].netif2 != null)) { for (var j in json[i].netif2) { var esc = obj.common.escapeFieldName(j); if (esc !== j) { json[i].netif2[esc] = json[i].netif2[j]; delete json[i].netif2[j]; } } } //if ((json[i].type == 'mesh') && (json[i].links != null)) { for (var j in json[i].links) { var esc = obj.common.escapeFieldName(j); if (esc !== j) { json[i].links[esc] = json[i].links[j]; delete json[i].links[j]; } } } - } + } //for (i in json) { if ((json[i].type == "node") && (json[i].host != null)) { json[i].rname = json[i].host; delete json[i].host; } } // DEBUG: Change host to rname setTimeout(function () { // If the Mongo database is being created for the first time, there is a race condition here. This will get around it. obj.db.RemoveAll(function () { @@ -1178,7 +1351,7 @@ function CreateMeshCentralServer(config, args) { } // Check if the database is capable of performing a backup - obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } }); + // Moved behind autobackup config init in startex4: obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } }); // Load configuration for database if needed if (obj.args.loadconfigfromdb) { @@ -1202,7 +1375,7 @@ function CreateMeshCentralServer(config, args) { for (i in args) { config2.settings[i] = args[i]; } // Lower case all keys in the config file - common.objKeysToLower(config2, ['ldapoptions', 'defaultuserwebstate', 'forceduserwebstate', 'httpheaders']); + common.objKeysToLower(config2, ['ldapoptions', 'defaultuserwebstate', 'forceduserwebstate', 'httpheaders', 'telegram/proxy']); // Grab some of the values from the original config.json file if present. config2['mysql'] = config['mysql']; @@ -1230,6 +1403,9 @@ function CreateMeshCentralServer(config, args) { obj.StartEx1b = async function () { var i; + // Add NodeJS version warning if needed + if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 16) { addServerWarning("MeshCentral will require Node v16 or above in the future, your current version is " + process.version + "."); } + // Setup certificate operations obj.certificateOperations = require('./certoperations.js').CertificateOperations(obj); @@ -1288,11 +1464,16 @@ function CreateMeshCentralServer(config, args) { if ((obj.config.domains[i].loginkey != null) && (obj.common.validateAlphaNumericArray(obj.config.domains[i].loginkey, 1, 128) == false)) { console.log("ERROR: Invalid login key, must be alpha-numeric string with no spaces."); process.exit(); return; } if (typeof obj.config.domains[i].agentkey == 'string') { obj.config.domains[i].agentkey = [obj.config.domains[i].agentkey]; } if ((obj.config.domains[i].agentkey != null) && (obj.common.validateAlphaNumericArray(obj.config.domains[i].agentkey, 1, 128) == false)) { console.log("ERROR: Invalid agent key, must be alpha-numeric string with no spaces."); process.exit(); return; } - if (typeof obj.config.domains[i].userallowedip == 'string') { if (obj.config.domains[i].userallowedip == '') { delete obj.config.domains[i].userallowedip; } else { obj.config.domains[i].userallowedip = obj.config.domains[i].userallowedip.split(','); } } - if (typeof obj.config.domains[i].userblockedip == 'string') { if (obj.config.domains[i].userblockedip == '') { delete obj.config.domains[i].userblockedip; } else { obj.config.domains[i].userblockedip = obj.config.domains[i].userblockedip.split(','); } } - if (typeof obj.config.domains[i].agentallowedip == 'string') { if (obj.config.domains[i].agentallowedip == '') { delete obj.config.domains[i].agentallowedip; } else { obj.config.domains[i].agentallowedip = obj.config.domains[i].agentallowedip.split(','); } } - if (typeof obj.config.domains[i].agentblockedip == 'string') { if (obj.config.domains[i].agentblockedip == '') { delete obj.config.domains[i].agentblockedip; } else { obj.config.domains[i].agentblockedip = obj.config.domains[i].agentblockedip.split(','); } } + obj.config.domains[i].userallowedip = obj.config.domains[i].userallowedip = readIpListFromFile(obj.config.domains[i].userallowedip); + obj.config.domains[i].userblockedip = obj.config.domains[i].userblockedip = readIpListFromFile(obj.config.domains[i].userblockedip); + obj.config.domains[i].agentallowedip = obj.config.domains[i].agentallowedip = readIpListFromFile(obj.config.domains[i].agentallowedip); + obj.config.domains[i].agentblockedip = obj.config.domains[i].agentblockedip = readIpListFromFile(obj.config.domains[i].agentblockedip); + if (typeof obj.config.domains[i].userallowedip == 'string') { if (obj.config.domains[i].userallowedip == '') { delete obj.config.domains[i].userallowedip; } else { obj.config.domains[i].userallowedip = obj.config.domains[i].userallowedip.split(' ').join('').split(','); } } + if (typeof obj.config.domains[i].userblockedip == 'string') { if (obj.config.domains[i].userblockedip == '') { delete obj.config.domains[i].userblockedip; } else { obj.config.domains[i].userblockedip = obj.config.domains[i].userblockedip.split(' ').join('').split(','); } } + if (typeof obj.config.domains[i].agentallowedip == 'string') { if (obj.config.domains[i].agentallowedip == '') { delete obj.config.domains[i].agentallowedip; } else { obj.config.domains[i].agentallowedip = obj.config.domains[i].agentallowedip.split(' ').join('').split(','); } } + if (typeof obj.config.domains[i].agentblockedip == 'string') { if (obj.config.domains[i].agentblockedip == '') { delete obj.config.domains[i].agentblockedip; } else { obj.config.domains[i].agentblockedip = obj.config.domains[i].agentblockedip.split(' ').join('').split(','); } } if (typeof obj.config.domains[i].ignoreagenthashcheck == 'string') { if (obj.config.domains[i].ignoreagenthashcheck == '') { delete obj.config.domains[i].ignoreagenthashcheck; } else { obj.config.domains[i].ignoreagenthashcheck = obj.config.domains[i].ignoreagenthashcheck.split(','); } } + if (typeof obj.config.domains[i].allowedorigin == 'string') { if (obj.config.domains[i].allowedorigin == '') { delete obj.config.domains[i].allowedorigin; } else { obj.config.domains[i].allowedorigin = obj.config.domains[i].allowedorigin.split(','); } } if ((obj.config.domains[i].passwordrequirements != null) && (typeof obj.config.domains[i].passwordrequirements == 'object')) { if (typeof obj.config.domains[i].passwordrequirements.skip2factor == 'string') { obj.config.domains[i].passwordrequirements.skip2factor = obj.config.domains[i].passwordrequirements.skip2factor.split(','); @@ -1366,7 +1547,7 @@ function CreateMeshCentralServer(config, args) { if (i == '') { addServerWarning("Unable to load Intel AMT TLS root certificate for default domain.", 5); } else { - addServerWarning("Unable to load Intel AMT TLS root certificate for domain " + i + ".", 6, [ i ]); + addServerWarning("Unable to load Intel AMT TLS root certificate for domain " + i + ".", 6, [i]); } } } @@ -1427,8 +1608,18 @@ function CreateMeshCentralServer(config, args) { if (obj.args.rediraliasport != null && (typeof obj.args.rediraliasport != 'number')) obj.args.rediraliasport = null; if (obj.args.redirport == null) obj.args.redirport = 80; if (obj.args.minifycore == null) obj.args.minifycore = false; - if (typeof args.agentidletimeout != 'number') { args.agentidletimeout = 150000; } else { args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec. - if ((obj.args.lanonly != true) && (obj.args.webrtconfig == null)) { obj.args.webrtconfig = { iceservers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun.services.mozilla.com' }] }; } // Setup default WebRTC STUN servers + if (typeof obj.args.agentidletimeout != 'number') { obj.args.agentidletimeout = 150000; } else { obj.args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec. + if ((obj.args.lanonly != true) && (typeof obj.args.webrtconfig == 'object')) { // fix incase you are using an old mis-spelt webrtconfig + obj.args.webrtcconfig = obj.args.webrtconfig; + delete obj.args.webrtconfig; + } + if ((obj.args.lanonly != true) && (obj.args.webrtcconfig == null)) { obj.args.webrtcconfig = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun.cloudflare.com:3478' }] }; } // Setup default WebRTC STUN servers + else if ((obj.args.lanonly != true) && (typeof obj.args.webrtcconfig == 'object')) { + if (obj.args.webrtcconfig.iceservers) { // webrtc is case-sensitive, so must rename iceservers to iceServers! + obj.args.webrtcconfig.iceServers = obj.args.webrtcconfig.iceservers; + delete obj.args.webrtcconfig.iceservers; + } + } if (typeof obj.args.ignoreagenthashcheck == 'string') { if (obj.args.ignoreagenthashcheck == '') { delete obj.args.ignoreagenthashcheck; } else { obj.args.ignoreagenthashcheck = obj.args.ignoreagenthashcheck.split(','); } } // Setup a site administrator @@ -1468,7 +1659,7 @@ function CreateMeshCentralServer(config, args) { } // Setup agent error log - if ((obj.config) && (obj.config.settings) && (obj.config.settings.agentlogdump != null)) { + if ((obj.config) && (obj.config.settings) && (obj.config.settings.agentlogdump)) { obj.fs.open(obj.path.join(obj.datapath, 'agenterrorlogs.txt'), 'a', function (err, fd) { obj.agentErrorLog = fd; }) } @@ -1804,19 +1995,31 @@ function CreateMeshCentralServer(config, args) { if (typeof config.settings.webpush.gcmapi == 'string') { webpush.setGCMAPIKey(config.settings.webpush.gcmapi); } } + // Get the current node version + const verSplit = process.version.substring(1).split('.'); + var nodeVersion = parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); + // Setup Firebase if ((config.firebase != null) && (typeof config.firebase.senderid == 'string') && (typeof config.firebase.serverkey == 'string')) { - obj.firebase = require('./firebase').CreateFirebase(obj, config.firebase.senderid, config.firebase.serverkey); + addServerWarning('Firebase now requires a service account JSON file, Firebase disabled.', 27); + } else if ((config.firebase != null) && (typeof config.firebase.serviceaccountfile == 'string')) { + var serviceAccount; + try { serviceAccount = JSON.parse(obj.fs.readFileSync(obj.path.join(obj.datapath, config.firebase.serviceaccountfile)).toString()); } catch (ex) { console.log(ex); } + if (serviceAccount != null) { obj.firebase = require('./firebase').CreateFirebase(obj, serviceAccount); } } else if ((typeof config.firebaserelay == 'object') && (typeof config.firebaserelay.url == 'string')) { // Setup the push messaging relay obj.firebase = require('./firebase').CreateFirebaseRelay(obj, config.firebaserelay.url, config.firebaserelay.key); } else if (obj.config.settings.publicpushnotifications === true) { - // Setup the Firebase push messaging relay using https://meshcentral.com, this is the public push notification server. - obj.firebase = require('./firebase').CreateFirebaseRelay(obj, 'https://meshcentral.com/firebaserelay.aspx'); + // Setup the Firebase push messaging relay using https://alt.meshcentral.com, this is the public push notification server. + obj.firebase = require('./firebase').CreateFirebaseRelay(obj, 'https://alt.meshcentral.com/firebaserelay.aspx'); } + // Setup monitoring + obj.monitoring = require('./monitoring.js').CreateMonitoring(obj, obj.args); + // Start periodic maintenance obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour + //obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 10 * 1); // DEBUG: Run this more often // Dispatch an event that the server is now running obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' }); @@ -1901,15 +2104,25 @@ function CreateMeshCentralServer(config, args) { obj.updateServerState('state', "running"); // Setup auto-backup defaults - if (obj.config.settings.autobackup == null) { obj.config.settings.autobackup = { backupintervalhours: 24, keeplastdaysbackup: 10 }; } - else if (obj.config.settings.autobackup === false) { delete obj.config.settings.autobackup; } - - // Check that autobackup path is not within the "meshcentral-data" folder. - if ((typeof obj.config.settings.autobackup == 'object') && (typeof obj.config.settings.autobackup.backuppath == 'string') && (obj.path.normalize(obj.config.settings.autobackup.backuppath).startsWith(obj.path.normalize(obj.datapath)))) { - addServerWarning("Backup path can't be set within meshcentral-data folder, backup settings ignored.", 21); - delete obj.config.settings.autobackup; + if (obj.config.settings.autobackup == false || obj.config.settings.autobackup == 'false') { obj.config.settings.autobackup = {backupintervalhours: 0}; } //no schedule, but able to console autobackup + else { + if (obj.config.settings.autobackup == null || obj.config.settings.autobackup === true) { obj.config.settings.autobackup = {backupintervalhours: 24, keeplastdaysbackup: 10}; }; + if (typeof obj.config.settings.autobackup.backupintervalhours != 'number') { obj.config.settings.autobackup.backupintervalhours = 24; }; + if (typeof obj.config.settings.autobackup.keeplastdaysbackup != 'number') { obj.config.settings.autobackup.keeplastdaysbackup = 10; }; + if (obj.config.settings.autobackup.backuphour != null ) { obj.config.settings.autobackup.backupintervalhours = 24; if ((typeof obj.config.settings.autobackup.backuphour != 'number') || (obj.config.settings.autobackup.backuphour > 23 || obj.config.settings.autobackup.backuphour < 0 )) { obj.config.settings.autobackup.backuphour = 0; }} + else {obj.config.settings.autobackup.backuphour = -1 }; + //arrayfi in case of string and remove possible ', ' space. !! If a string instead of an array is passed, it will be split by ',' so *{.txt,.log} won't work in that case !! + if (!obj.config.settings.autobackup.backupignorefilesglob) {obj.config.settings.autobackup.backupignorefilesglob = []} + else if (typeof obj.config.settings.autobackup.backupignorefilesglob == 'string') { obj.config.settings.autobackup.backupignorefilesglob = obj.config.settings.autobackup.backupignorefilesglob.replaceAll(', ', ',').split(','); }; + if (!obj.config.settings.autobackup.backupskipfoldersglob) {obj.config.settings.autobackup.backupskipfoldersglob = []} + else if (typeof obj.config.settings.autobackup.backupskipfoldersglob == 'string') { obj.config.settings.autobackup.backupskipfoldersglob = obj.config.settings.autobackup.backupskipfoldersglob.replaceAll(', ', ',').split(','); }; + if (typeof obj.config.settings.autobackup.backuppath == 'string') { obj.backuppath = (obj.config.settings.autobackup.backuppath = (obj.path.resolve(obj.config.settings.autobackup.backuppath))) } else { obj.config.settings.autobackup.backuppath = obj.backuppath }; + if (typeof obj.config.settings.autobackup.backupname != 'string') { obj.config.settings.autobackup.backupname = 'meshcentral-autobackup-'}; } + // Check if the database is capable of performing a backup + obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } }); + // Load Intel AMT passwords from the "amtactivation.log" file obj.loadAmtActivationLogPasswords(function (amtPasswords) { obj.amtPasswords = amtPasswords; @@ -2070,14 +2283,19 @@ function CreateMeshCentralServer(config, args) { // Check if we need to perform an automatic backup function checkAutobackup() { - if (obj.config.settings.autobackup && (typeof obj.config.settings.autobackup.backupintervalhours == 'number')) { + if (obj.config.settings.autobackup.backupintervalhours >= 1 ) { obj.db.Get('LastAutoBackupTime', function (err, docs) { - if (err != null) return; + if (err != null) { console.error("checkAutobackup: Error getting LastBackupTime from DB"); return} var lastBackup = 0; - const now = new Date().getTime(); + const currentdate = new Date(); + let currentHour = currentdate.getHours(); + let now = currentdate.getTime(); if (docs.length == 1) { lastBackup = docs[0].value; } const delta = now - lastBackup; - if (delta > (obj.config.settings.autobackup.backupintervalhours * 60 * 60 * 1000)) { + //const delta = 9999999999; // DEBUG: backup always + obj.debug ('backup', 'Entering checkAutobackup, lastAutoBackupTime: ' + new Date(lastBackup).toLocaleString('default', { dateStyle: 'medium', timeStyle: 'short' }) + ', delta: ' + (delta/(1000*60*60)).toFixed(2) + ' hours'); + //start autobackup if interval has passed or at configured hour, whichever comes first. When an hour schedule is missed, it will make a backup immediately. + if ((delta > (obj.config.settings.autobackup.backupintervalhours * 60 * 60 * 1000)) || ((currentHour == obj.config.settings.autobackup.backuphour) && (delta >= 2 * 60 * 60 * 1000))) { // A new auto-backup is required. obj.db.Set({ _id: 'LastAutoBackupTime', value: now }); // Save the current time in the database obj.db.performBackup(); // Perform the backup @@ -2136,7 +2354,7 @@ function CreateMeshCentralServer(config, args) { // Update the server state obj.updateServerState('state', "stopped"); }; - + // Event Dispatch obj.AddEventDispatch = function (ids, target) { obj.debug('dispatch', 'AddEventDispatch', ids); @@ -2199,6 +2417,10 @@ function CreateMeshCentralServer(config, args) { storeEvent.links = Object.assign({}, storeEvent.links); for (var i in storeEvent.links) { var ue = obj.common.escapeFieldName(i); if (ue !== i) { storeEvent.links[ue] = storeEvent.links[i]; delete storeEvent.links[i]; } } } + if (storeEvent.mesh) { + // Escape "mesh" names that may have "." and/or "$" + storeEvent.mesh = obj.common.escapeLinksFieldNameEx(storeEvent.mesh); + } storeEvent.ids = ids; obj.db.StoreEvent(storeEvent); } @@ -2289,7 +2511,7 @@ function CreateMeshCentralServer(config, args) { // Event any changes on this server only if ((newConnectivity != oldPowerState) || (newPowerState != oldPowerState)) { - obj.DispatchEvent(obj.webserver.CreateNodeDispatchTargets(meshid, nodeid), obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, domain: nodeid.split('/')[1], conn: newConnectivity, pwr: newPowerState, nolog: 1, nopeers: 1 }); + obj.DispatchEvent(obj.webserver.CreateNodeDispatchTargets(meshid, nodeid), obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, domain: nodeid.split('/')[1], conn: newConnectivity, pwr: newPowerState, nolog: 1, nopeers: 1, id: Math.random() }); } } }; @@ -2302,7 +2524,7 @@ function CreateMeshCentralServer(config, args) { const domainId = meshSplit[1]; if (obj.config.domains[domainId] == null) return; const mailserver = obj.config.domains[domainId].mailserver; - if (mailserver == null) return; + if ((mailserver == null) && (obj.msgserver == null)) return; // Get the device group for this device const mesh = obj.webserver.meshes[meshid]; @@ -2322,7 +2544,7 @@ function CreateMeshCentralServer(config, args) { // Check if any user needs email notification for (var i in users) { const user = obj.webserver.users[users[i]]; - if ((user != null) && (user.email != null) && (user.emailVerified == true)) { + if (user != null) { var notify = 0; // Device group notifications @@ -2335,7 +2557,8 @@ function CreateMeshCentralServer(config, args) { if (user.notify[nodeid] != null) { notify |= user.notify[nodeid]; } } - if ((notify & 48) != 0) { + // Email notifications + if ((user.email != null) && (user.emailVerified == true) && (mailserver != null) && ((notify & 48) != 0)) { if (stateSet == true) { if ((notify & 16) != 0) { mailserver.notifyDeviceConnect(user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo); @@ -2351,6 +2574,24 @@ function CreateMeshCentralServer(config, args) { } } } + + // Messaging notifications + if ((obj.msgserver != null) && ((notify & 384) != 0)) { + if (stateSet == true) { + if ((notify & 128) != 0) { + obj.msgserver.notifyDeviceConnect(user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo); + } else { + obj.msgserver.cancelNotifyDeviceDisconnect(user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo); + } + } + else if (stateSet == false) { + if ((notify & 256) != 0) { + obj.msgserver.notifyDeviceDisconnect(user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo); + } else { + obj.msgserver.cancelNotifyDeviceConnect(user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo); + } + } + } } } } @@ -2365,7 +2606,7 @@ function CreateMeshCentralServer(config, args) { const domainId = meshSplit[1]; if (obj.config.domains[domainId] == null) return; const mailserver = obj.config.domains[domainId].mailserver; - if (mailserver == null) return; + if ((mailserver == null) && (obj.msgserver == null)) return; // Get the device group for this device const mesh = obj.webserver.meshes[meshid]; @@ -2385,7 +2626,7 @@ function CreateMeshCentralServer(config, args) { // Check if any user needs email notification for (var i in users) { const user = obj.webserver.users[users[i]]; - if ((user != null) && (user.email != null) && (user.emailVerified == true)) { + if (user != null) { var notify = 0; // Device group notifications @@ -2398,9 +2639,11 @@ function CreateMeshCentralServer(config, args) { if (user.notify[nodeid] != null) { notify |= user.notify[nodeid]; } } - if ((notify & 64) != 0) { - mailserver.sendDeviceHelpMail(domain, user.name, user.email, devicename, nodeid, helpusername, helprequest, user.llang); - } + // Mail help request + if ((user.email != null) && (user.emailVerified == true) && ((notify & 64) != 0)) { mailserver.sendDeviceHelpMail(domain, user.name, user.email, devicename, nodeid, helpusername, helprequest, user.llang); } + + // Message help request + if ((user.msghandle != null) && ((notify & 512) != 0)) { obj.msgserver.sendDeviceHelpRequest(domain, user.name, user.msghandle, devicename, nodeid, helpusername, helprequest, user.llang); } } } } @@ -2437,7 +2680,7 @@ function CreateMeshCentralServer(config, args) { if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; } var powerState = 0, oldPowerState = state.powerState; if ((state.connectivity & 1) != 0) { powerState = state.agentPower; } else if ((state.connectivity & 2) != 0) { powerState = state.ciraPower; } else if ((state.connectivity & 4) != 0) { powerState = state.amtPower; } - if ((state.powerState == null) || (state.powerState != powerState)) { + if ((state.powerState == null) || (state.powerState == undefined) || (state.powerState != powerState)) { state.powerState = powerState; eventConnectChange = 1; @@ -2449,7 +2692,7 @@ function CreateMeshCentralServer(config, args) { // Event the node connection change if (eventConnectChange == 1) { - obj.DispatchEvent(obj.webserver.CreateNodeDispatchTargets(meshid, nodeid), obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, domain: nodeid.split('/')[1], conn: state.connectivity, pwr: state.powerState, ct: connectTime, nolog: 1, nopeers: 1 }); + obj.DispatchEvent(obj.webserver.CreateNodeDispatchTargets(meshid, nodeid), obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, domain: nodeid.split('/')[1], conn: state.connectivity, pwr: state.powerState, ct: connectTime, nolog: 1, nopeers: 1, id: Math.random() }); // Save indication of node connection change const lc = { _id: 'lc' + nodeid, type: 'lastconnect', domain: nodeid.split('/')[1], meshid: meshid, time: Date.now(), cause: 1, connectType: connectType }; @@ -2481,7 +2724,7 @@ function CreateMeshCentralServer(config, args) { if (connectType == 1) { state.agentPower = powerState; } else if (connectType == 2) { state.ciraPower = powerState; } else if (connectType == 4) { state.amtPower = powerState; } var powerState = 0, oldPowerState = state.powerState; if ((state.connectivity & 1) != 0) { powerState = state.agentPower; } else if ((state.connectivity & 2) != 0) { powerState = state.ciraPower; } else if ((state.connectivity & 4) != 0) { powerState = state.amtPower; } - if ((state.powerState == null) || (state.powerState != powerState)) { + if ((state.powerState == null) || (state.powerState == undefined) || (state.powerState != powerState)) { state.powerState = powerState; eventConnectChange = 1; @@ -2553,7 +2796,7 @@ function CreateMeshCentralServer(config, args) { // Event the node connection change if (eventConnectChange == 1) { - obj.DispatchEvent(obj.webserver.CreateNodeDispatchTargets(meshid, nodeid), obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, domain: nodeid.split('/')[1], conn: state.connectivity, pwr: state.powerState, nolog: 1, nopeers: 1 }); + obj.DispatchEvent(obj.webserver.CreateNodeDispatchTargets(meshid, nodeid), obj, { action: 'nodeconnect', meshid: meshid, nodeid: nodeid, domain: nodeid.split('/')[1], conn: state.connectivity, pwr: state.powerState, nolog: 1, nopeers: 1, id: Math.random() }); // Notify any users of device disconnection obj.NotifyUserOfDeviceStateChange(meshid, nodeid, Date.now(), connectType, -1, serverid, false, extraInfo); @@ -2623,7 +2866,7 @@ function CreateMeshCentralServer(config, args) { if (obj.fs.existsSync(obj.path.join(meshcorePath, 'meshcore.js')) == false) { meshcorePath = obj.path.join(__dirname, 'agents'); if (obj.fs.existsSync(obj.path.join(meshcorePath, 'meshcore.js')) == false) { - obj.defaultMeshCores = obj.defaultMeshCoresHash = { }; if (func != null) { func(false); } // meshcore.js not found + obj.defaultMeshCores = obj.defaultMeshCoresHash = {}; if (func != null) { func(false); } // meshcore.js not found } } @@ -2689,7 +2932,7 @@ function CreateMeshCentralServer(config, args) { // We are adding a JS file to the meshcores var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3); if (moduleName.endsWith('.min')) { moduleName = moduleName.substring(0, moduleName.length - 4); } // Remove the ".min" for ".min.js" files. - const moduleData = [ 'try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (ex) { }\r\n' ]; + const moduleData = ['try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (ex) { }\r\n']; // Merge this module // NOTE: "smbios" module makes some non-AI Linux segfault, only include for IA platforms. @@ -2918,7 +3161,7 @@ function CreateMeshCentralServer(config, args) { } catch (ex) { } } }; - + // List of possible mesh agents obj.meshAgentsArchitectureNumbers = { 0: { id: 0, localname: 'Unknown', rname: 'meshconsole.exe', desc: 'Unknown agent', update: false, amt: true, platform: 'unknown', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, @@ -2935,7 +3178,7 @@ function CreateMeshCentralServer(config, args) { 11: { id: 11, localname: 'meshagent_osx-x86-32', rname: 'meshosx', desc: 'Apple macOS x86-32', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // Apple x86-32 binary, no longer supported. 12: { id: 12, localname: 'MeshAgent-Android-x86', rname: 'meshandroid', desc: 'Android x86-32', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, 13: { id: 13, localname: 'meshagent_pogo', rname: 'meshagent', desc: 'Linux ARM PogoPlug', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, - 14: { id: 14, localname: 'MeshAgent-Android-APK', rname: 'meshandroid', desc: 'Android', update: false, amt: false, platform: 'android', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // Get this one from Google Play + 14: { id: 14, localname: 'meshagent_android.apk', rname: 'meshandroid.apk', desc: 'Android', update: false, amt: false, platform: 'android', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // Get this one from Google Play 15: { id: 15, localname: 'meshagent_poky', rname: 'meshagent', desc: 'Linux Poky x86-32', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, 16: { id: 16, localname: 'meshagent_osx-x86-64', rname: 'meshagent', desc: 'Apple macOS x86-64', update: true, amt: false, platform: 'osx', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // Apple x86-64 binary 17: { id: 17, localname: 'MeshAgent-ChromeOS', rname: 'meshagent', desc: 'Google ChromeOS', update: false, amt: false, platform: 'chromeos', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // Get this one from Chrome store @@ -2960,12 +3203,15 @@ function CreateMeshCentralServer(config, args) { 37: { id: 37, localname: 'meshagent_openbsd_x86-64', rname: 'meshagent', desc: 'OpenBSD x86-64', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // OpenBSD x86-64 40: { id: 40, localname: 'meshagent_mipsel24kc', rname: 'meshagent', desc: 'Linux MIPSEL24KC (OpenWRT)', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // MIPS Router with OpenWRT 41: { id: 41, localname: 'meshagent_aarch64-cortex-a53', rname: 'meshagent', desc: 'ARMADA/CORTEX-A53/MUSL (OpenWRT)', update: true, amt: false, platform: 'linux', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // OpenWRT Routers + 42: { id: 42, localname: 'MeshConsoleARM64.exe', rname: 'meshconsolearm64.exe', desc: 'Windows ARM-64 console', update: true, amt: true, platform: 'win32', core: 'windows-amt', rcore: 'windows-recovery', arcore: 'windows-agentrecovery', tcore: 'windows-tiny' }, + 43: { id: 43, localname: 'MeshServiceARM64.exe', rname: 'meshagentarm64.exe', desc: 'Windows ARM-64 service', update: true, amt: true, platform: 'win32', core: 'windows-amt', rcore: 'windows-recovery', arcore: 'windows-agentrecovery', tcore: 'windows-tiny', codesign: true }, 10003: { id: 10003, localname: 'MeshService.exe', rname: 'meshagent32.exe', desc: 'Windows x86-32 service', update: true, amt: true, platform: 'win32', core: 'windows-amt', rcore: 'windows-recovery', arcore: 'windows-agentrecovery', tcore: 'windows-tiny', unsigned: true }, 10004: { id: 10004, localname: 'MeshService64.exe', rname: 'meshagent64.exe', desc: 'Windows x86-64 service', update: true, amt: true, platform: 'win32', core: 'windows-amt', rcore: 'windows-recovery', arcore: 'windows-agentrecovery', tcore: 'windows-tiny', unsigned: true }, 10005: { id: 10005, localname: 'meshagent_osx-universal-64', rname: 'meshagent', desc: 'Apple macOS Universal Binary', update: true, amt: false, platform: 'osx', core: 'linux-noamt', rcore: 'linux-recovery', arcore: 'linux-agentrecovery', tcore: 'linux-tiny' }, // Apple Silicon + x86 universal binary 10006: { id: 10006, localname: 'MeshCentralAssistant.exe', rname: 'MeshCentralAssistant.exe', desc: 'MeshCentral Assistant for Windows', update: false, amt: false, platform: 'win32' }, // MeshCentral Assistant - 11000: { id: 11000, localname: 'MeshCmd.exe', rname: 'MeshCmd.exe', desc: 'Windows x86-32 meshcmd', update: false, amt: true, platform: 'win32', codesign: true }, // MeshCMD for Windows 32-bit - 11001: { id: 11001, localname: 'MeshCmd64.exe', rname: 'MeshCmd64.exe', desc: 'Windows x86-64 meshcmd', update: false, amt: true, platform: 'win32', codesign: true } // MeshCMD for Windows 64-bit + 11000: { id: 11000, localname: 'MeshCmd.exe', rname: 'MeshCmd.exe', desc: 'Windows x86-32 meshcmd', update: false, amt: true, platform: 'win32', codesign: true }, // MeshCMD for Windows x86 32-bit + 11001: { id: 11001, localname: 'MeshCmd64.exe', rname: 'MeshCmd64.exe', desc: 'Windows x86-64 meshcmd', update: false, amt: true, platform: 'win32', codesign: true }, // MeshCMD for Windows x86 64-bit + 11002: { id: 11002, localname: 'MeshCmdARM64.exe', rname: 'MeshCmdARM64.exe', desc: 'Windows ARM-64 meshcmd', update: false, amt: true, platform: 'win32', codesign: true } // MeshCMD for Windows ARM 64-bit }; // Sign windows agents @@ -3008,13 +3254,13 @@ function CreateMeshCentralServer(config, args) { // Setup the time server var timeStampUrl = 'http://timestamp.comodoca.com/authenticode'; - if (args.agenttimestampserver === false) { timeStampUrl = null; } - else if (typeof args.agenttimestampserver == 'string') { timeStampUrl = args.agenttimestampserver; } + if (obj.args.agenttimestampserver === false) { timeStampUrl = null; } + else if (typeof obj.args.agenttimestampserver == 'string') { timeStampUrl = obj.args.agenttimestampserver; } // Setup the time server proxy var timeStampProxy = null; - if (typeof args.agenttimestampproxy == 'string') { timeStampProxy = args.agenttimestampproxy; } - else if ((args.agenttimestampproxy !== false) && (typeof args.npmproxy == 'string')) { timeStampProxy = args.npmproxy; } + if (typeof obj.args.agenttimestampproxy == 'string') { timeStampProxy = obj.args.agenttimestampproxy; } + else if ((obj.args.agenttimestampproxy !== false) && (typeof obj.args.npmproxy == 'string')) { timeStampProxy = obj.args.npmproxy; } // Setup the pending operations counter var pendingOperations = 1; @@ -3161,7 +3407,7 @@ function CreateMeshCentralServer(config, args) { console.log(obj.common.format('Code signed {0}.', agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname)); } else { // Failed to sign agent - addServerWarning('Failed to sign \"' + agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname + '\": ' + err, 22, [ agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname, err ]); + addServerWarning('Failed to sign \"' + agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname + '\": ' + err, 22, [agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname, err]); } if (--pendingOperations === 0) { agentSignedFunc.func(); } } @@ -3499,7 +3745,7 @@ function CreateMeshCentralServer(config, args) { try { const iv = Buffer.from(obj.crypto.randomBytes(12), 'binary'), cipher = obj.crypto.createCipheriv('aes-256-gcm', key.slice(0, 32), iv); const crypted = Buffer.concat([cipher.update(JSON.stringify(data), 'utf8'), cipher.final()]); - return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString(obj.args.cookieencoding ? obj.args.cookieencoding : 'base64'); + return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString(obj.args.cookieencoding ? obj.args.cookieencoding : 'base64').replace(/\+/g, '@').replace(/\//g, '$'); } catch (ex) { return null; } } @@ -3508,7 +3754,7 @@ function CreateMeshCentralServer(config, args) { if ((typeof data != 'string') || (data.length < 13)) return {}; if (key == null) { key = obj.loginCookieEncryptionKey; } try { - const buf = Buffer.from(data, 'base64'); + const buf = Buffer.from(data.replace(/\@/g, '+').replace(/\$/g, '/'), obj.args.cookieencoding ? obj.args.cookieencoding : 'base64'); const decipher = obj.crypto.createDecipheriv('aes-256-gcm', key.slice(0, 32), buf.slice(0, 12)); decipher.setAuthTag(buf.slice(12, 28)); return JSON.parse(decipher.update(buf.slice(28), 'binary', 'utf8') + decipher.final('utf8')); @@ -3630,7 +3876,7 @@ function CreateMeshCentralServer(config, args) { // Send event to log file if (obj.config.settings && obj.config.settings.log) { if (typeof obj.args.log == 'string') { obj.args.log = obj.args.log.split(','); } - if (obj.args.log.indexOf(source) >= 0) { + if ((obj.args.log.indexOf(source) >= 0) || (obj.args.log[0] == '*')) { const d = new Date(); if (obj.xxLogFile == null) { try { @@ -3642,7 +3888,8 @@ function CreateMeshCentralServer(config, args) { if (obj.xxLogFile != null) { try { if (obj.xxLogDateStr != d.toLocaleDateString()) { obj.xxLogDateStr = d.toLocaleDateString(); obj.fs.writeSync(obj.xxLogFile, '---- ' + d.toLocaleDateString() + ' ----\r\n'); } - obj.fs.writeSync(obj.xxLogFile, new Date().toLocaleTimeString() + ' - ' + source + ': ' + args.join(', ') + '\r\n'); + const formattedArgs = args.map(function (arg) { return (typeof arg === 'object' && arg !== null) ? JSON.stringify(arg) : arg; }); + obj.fs.writeSync(obj.xxLogFile, new Date().toLocaleTimeString() + ' - ' + source + ': ' + formattedArgs.join(', ') + '\r\n'); } catch (ex) { } } } @@ -3686,7 +3933,7 @@ function CreateMeshCentralServer(config, args) { function readIpListFromFile(arg) { if ((typeof arg != 'string') || (!arg.startsWith('file:'))) return arg; var lines = null; - try { lines = obj.fs.readFileSync(obj.path.join(obj.datapath, arg.substring(5))).toString().split('\r\n').join('\r').split('\r'); } catch (ex) { } + try { lines = obj.fs.readFileSync(obj.path.join(obj.datapath, arg.substring(5))).toString().split(/\r?\n/).join('\r').split('\r'); } catch (ex) { } if (lines == null) return null; const validLines = []; for (var i in lines) { if ((lines[i].length > 0) && (((lines[i].charAt(0) > '0') && (lines[i].charAt(0) < '9')) || (lines[i].charAt(0) == ':'))) validLines.push(lines[i]); } @@ -3699,6 +3946,7 @@ function CreateMeshCentralServer(config, args) { function logWarnEvent(msg) { if (obj.servicelog != null) { obj.servicelog.warn(msg); } console.log(msg); } function logErrorEvent(msg) { if (obj.servicelog != null) { obj.servicelog.error(msg); } console.error(msg); } obj.getServerWarnings = function () { return serverWarnings; } + // TODO: migrate from other addServerWarning function and add timestamp obj.addServerWarning = function (msg, id, args, print) { serverWarnings.push({ msg: msg, id: id, args: args }); if (print !== false) { console.log("WARNING: " + msg); } } // auth.log functions @@ -3714,9 +3962,9 @@ function CreateMeshCentralServer(config, args) { if (obj.authlogfile != null) { // Write authlog to file try { const d = new Date(), month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][d.getMonth()]; - msg = month + ' ' + d.getDate() + ' ' + obj.common.zeroPad(d.getHours(), 2) + ':' + obj.common.zeroPad(d.getMinutes(), 2) + ':' + d.getSeconds() + ' meshcentral ' + server + '[' + process.pid + ']: ' + msg + ((obj.platform == 'win32') ? '\r\n' : '\n'); - obj.fs.write(obj.authlogfile, msg, function (err, written, string) { }); - } catch (ex) { console.log(ex); } + str = month + ' ' + d.getDate() + ' ' + obj.common.zeroPad(d.getHours(), 2) + ':' + obj.common.zeroPad(d.getMinutes(), 2) + ':' + d.getSeconds() + ' meshcentral ' + server + '[' + process.pid + ']: ' + msg + ((obj.platform == 'win32') ? '\r\n' : '\n'); + obj.fs.write(obj.authlogfile, str, function (err, written, string) { if (err) { console.error(err); } }); + } catch (ex) { console.error(ex); } } } @@ -3737,7 +3985,7 @@ function CreateMeshCentralServer(config, args) { function checkResolveAll(names, func) { const dns = require('dns'), state = { func: func, count: names.length, err: null }; for (var i in names) { - dns.resolve(names[i], function (err, records) { + dns.lookup(names[i], { all: true }, function (err, records) { if (err != null) { if (this.state.err == null) { this.state.err = [this.name]; } else { this.state.err.push(this.name); } } if (--this.state.count == 0) { this.state.func(this.state.err); } }.bind({ name: names[i], state: state })) @@ -3759,9 +4007,7 @@ function getConfig(createSampleConfig) { // Read configuration file if present and change arguments. var config = {}, configFilePath = path.join(datapath, 'config.json'); - if (args.configfile) { - configFilePath = common.joinPath(datapath, args.configfile); - } + if (args.configfile) { configFilePath = common.joinPath(datapath, args.configfile); } if (fs.existsSync(configFilePath)) { // Load and validate the configuration file try { config = require(configFilePath); } catch (ex) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; } @@ -3781,7 +4027,7 @@ function getConfig(createSampleConfig) { // Lower case all keys in the config file try { - require('./common.js').objKeysToLower(config, ['ldapoptions', 'defaultuserwebstate', 'forceduserwebstate', 'httpheaders']); + require('./common.js').objKeysToLower(config, ['ldapoptions', 'defaultuserwebstate', 'forceduserwebstate', 'httpheaders', 'telegram/proxy']); } catch (ex) { console.log('CRITICAL ERROR: Unable to access the file \"./common.js\".\r\nCheck folder & file permissions.'); process.exit(); @@ -3791,21 +4037,38 @@ function getConfig(createSampleConfig) { } // Check if a list of modules are present and install any missing ones -function InstallModules(modules, func) { - const missingModules = []; +function InstallModules(modules, args, func) { + var missingModules = []; if (modules.length > 0) { const dependencies = require('./package.json').dependencies; for (var i in modules) { // Modules may contain a version tag (foobar@1.0.0), remove it so the module can be found using require const moduleNameAndVersion = modules[i]; - const moduleInfo = moduleNameAndVersion.split('@', 2); - var moduleName = moduleInfo[0]; - var moduleVersion = moduleInfo[1]; - if (moduleName == '') { moduleName = moduleNameAndVersion; moduleVersion = null; } // If the module name starts with @, don't use @ as a version seperator. + const moduleInfo = moduleNameAndVersion.split('@', 3); + var moduleName = null; + var moduleVersion = null; + if(moduleInfo.length == 1){ // normal package without version + moduleName = moduleInfo[0]; + } else if (moduleInfo.length == 2) { // normal package with a version OR custom repo package with no version + moduleName = moduleInfo[0] === '' ? moduleNameAndVersion : moduleInfo[0]; + moduleVersion = moduleInfo[0] === '' ? null : moduleInfo[1]; + } else if (moduleInfo.length == 3) { // custom repo package and package with a version + moduleName = "@" + moduleInfo[1]; + moduleVersion = moduleInfo[2]; + } try { // Does the module need a specific version? if (moduleVersion) { - if (require(`${moduleName}/package.json`).version != moduleVersion) { throw new Error(); } + var versionMatch = false; + var modulePath = null; + // This is the first way to test if a module is already installed. + try { versionMatch = (require(`${moduleName}/package.json`).version == moduleVersion) } catch (ex) { + if (ex.code == "ERR_PACKAGE_PATH_NOT_EXPORTED") { modulePath = ("" + ex).split(' ').at(-1); } else { throw new Error(); } + } + // If the module is not installed, but we get the ERR_PACKAGE_PATH_NOT_EXPORTED error, try a second way. + if ((versionMatch == false) && (modulePath != null)) { + if (JSON.parse(require('fs').readFileSync(modulePath, 'utf8')).version != moduleVersion) { throw new Error(); } + } } else { // For all other modules, do the check here. // Is the module in package.json? Install exact version. @@ -3813,32 +4076,39 @@ function InstallModules(modules, func) { require(moduleName); } } catch (ex) { - if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(moduleNameAndVersion); } + missingModules.push(moduleNameAndVersion); } } - if (missingModules.length > 0) { InstallModule(missingModules.shift(), InstallModules, modules, func); } else { func(); } + + if (missingModules.length > 0) { if (args.debug) { console.log('Missing Modules: ' + missingModules.join(', ')); } InstallModuleEx(missingModules, args, func); } else { func(); } } } -// Check if a module is present and install it if missing -function InstallModule(modulename, func, tag1, tag2) { - console.log('Installing ' + modulename + '...'); +// Install all missing modules at once. We will be running "npm install" once, with a full list of all modules we need, no matter if they area already installed or not, +// this is to make sure NPM gives us exactly what we need. Also, we install the meshcentral with current version, so that NPM does not update it - which it will do if obmitted. +function InstallModuleEx(modulenames, args, func) { + var names = modulenames.join(' '); + console.log('Installing modules', modulenames); const child_process = require('child_process'); var parentpath = __dirname; + function getCurrentVersion() { try { return JSON.parse(require('fs').readFileSync(require('path').join(__dirname, 'package.json'), 'utf8')).version; } catch (ex) { } return null; } // Fetch server version + //const meshCentralVersion = getCurrentVersion(); + //if ((meshCentralVersion != null) && (args.dev == null)) { names = 'meshcentral@' + getCurrentVersion() + ' ' + names; } // Get the working directory if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) { parentpath = require('path').join(__dirname, '../..'); } - child_process.exec(npmpath + ` install --no-package-lock --no-optional ${modulename}`, { maxBuffer: 512000, timeout: 120000, cwd: parentpath }, function (error, stdout, stderr) { + if (args.debug) { console.log('NPM Command Line: ' + npmpath + ` install --save-exact --no-audit --omit=optional --no-fund ${names}`); } + // always use --save-exact - https://stackoverflow.com/a/64507176/1210734 + child_process.exec(npmpath + ` install --save-exact --no-audit --no-optional --omit=optional ${names}`, { maxBuffer: 512000, timeout: 300000, cwd: parentpath }, function (error, stdout, stderr) { if ((error != null) && (error != '')) { var mcpath = __dirname; if (mcpath.endsWith('\\node_modules\\meshcentral') || mcpath.endsWith('/node_modules/meshcentral')) { mcpath = require('path').join(mcpath, '..', '..'); } - console.log('ERROR: Unable to install required module "' + modulename + '". MeshCentral may not have access to npm, or npm may not have suffisent rights to load the new module. To manualy install this module try:\r\n\r\n cd "' + mcpath + '"\r\n npm install ' + modulename + '\r\n node node_modules' + ((require('os').platform() == 'win32') ? '\\' : '/') + 'meshcentral'); + console.log('ERROR: Unable to install required modules. MeshCentral may not have access to npm, or npm may not have suffisent rights to load the new module. To manualy install this module try:\r\n\r\n cd "' + mcpath + '"\r\n npm install --no-audit --no-optional --omit=optional ' + names + '\r\n node node_modules' + ((require('os').platform() == 'win32') ? '\\' : '/') + 'meshcentral'); process.exit(); return; } - previouslyInstalledModules[modulename] = true; - func(tag1, tag2); + func(); return; }); } @@ -3847,12 +4117,13 @@ function InstallModule(modulename, func, tag1, tag2) { process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); }); // Add a server warning, warnings will be shown to the administrator on the web application +// TODO: migrate to obj.addServerWarning? const serverWarnings = []; function addServerWarning(msg, id, args, print) { serverWarnings.push({ msg: msg, id: id, args: args }); if (print !== false) { console.log("WARNING: " + msg); } } /* var ServerWarnings = { - 1: "MeshCentral SSH support requires NodeJS 11 or higher.", + 1: "", 2: "Missing WebDAV parameters.", 3: "Unrecognized configuration option \"{0}\".", 4: "WebSocket compression is disabled, this feature is broken in NodeJS v11.11 to v12.15 and v13.2", @@ -3877,7 +4148,8 @@ var ServerWarnings = { 23: "Unable to load agent icon file: {0}.", 24: "Unable to load agent logo file: {0}.", 25: "This NodeJS version does not support OpenID.", - 26: "This NodeJS version does not support Discord.js." + 26: "This NodeJS version does not support Discord.js.", + 27: "Firebase now requires a service account JSON file, Firebase disabled." }; */ @@ -3887,14 +4159,14 @@ var meshserver = null; var childProcess = null; var previouslyInstalledModules = {}; function mainStart() { - // Check the NodeJS is version 10 or better. - if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 10) { console.log("MeshCentral requires Node v10 or above, current version is " + process.version + "."); return; } + // Check the NodeJS is version 16 or better. + if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 16) { console.log("MeshCentral requires Node v16 or above, current version is " + process.version + "."); return; } // If running within the node_modules folder, move working directory to the parent of the node_modules folder. if (__dirname.endsWith('\\node_modules\\meshcentral') || __dirname.endsWith('/node_modules/meshcentral')) { process.chdir(require('path').join(__dirname, '..', '..')); } // Check for any missing modules. - InstallModules(['minimist'], function () { + InstallModules(['minimist'], {}, function () { // Parse inbound arguments const args = require('minimist')(process.argv.slice(2)); @@ -3931,7 +4203,7 @@ function mainStart() { // Check if Windows SSPI, LDAP, Passport and YubiKey OTP will be used var sspi = false; var ldap = false; - var passport = null; + var passport = []; var allsspi = true; var yubikey = false; var ssh = false; @@ -3950,60 +4222,72 @@ function mainStart() { if (config.domains[i].yubikey != null) { yubikey = true; } if (config.domains[i].auth == 'ldap') { ldap = true; } if (mstsc == false) { config.domains[i].mstsc = false; } - if (config.domains[i].ssh == true) { if (nodeVersion < 11) { config.domains[i].ssh = false; } ssh = true; } + if (config.domains[i].ssh == true) { ssh = true; } if ((typeof config.domains[i].authstrategies == 'object')) { - if (passport == null) { passport = ['passport@0.5.3']; } // Passport v0.6.0 is broken with cookie-session, see https://github.com/jaredhanson/passport/issues/904 + if (passport.indexOf('passport') == -1) { passport.push('passport','connect-flash'); } // Passport v0.6.0 requires a patch, see https://github.com/jaredhanson/passport/issues/904 and include connect-flash here to display errors if ((typeof config.domains[i].authstrategies.twitter == 'object') && (typeof config.domains[i].authstrategies.twitter.clientid == 'string') && (typeof config.domains[i].authstrategies.twitter.clientsecret == 'string') && (passport.indexOf('passport-twitter') == -1)) { passport.push('passport-twitter'); } if ((typeof config.domains[i].authstrategies.google == 'object') && (typeof config.domains[i].authstrategies.google.clientid == 'string') && (typeof config.domains[i].authstrategies.google.clientsecret == 'string') && (passport.indexOf('passport-google-oauth20') == -1)) { passport.push('passport-google-oauth20'); } if ((typeof config.domains[i].authstrategies.github == 'object') && (typeof config.domains[i].authstrategies.github.clientid == 'string') && (typeof config.domains[i].authstrategies.github.clientsecret == 'string') && (passport.indexOf('passport-github2') == -1)) { passport.push('passport-github2'); } - if ((typeof config.domains[i].authstrategies.reddit == 'object') && (typeof config.domains[i].authstrategies.reddit.clientid == 'string') && (typeof config.domains[i].authstrategies.reddit.clientsecret == 'string') && (passport.indexOf('passport-reddit') == -1)) { passport.push('passport-reddit'); } if ((typeof config.domains[i].authstrategies.azure == 'object') && (typeof config.domains[i].authstrategies.azure.clientid == 'string') && (typeof config.domains[i].authstrategies.azure.clientsecret == 'string') && (typeof config.domains[i].authstrategies.azure.tenantid == 'string') && (passport.indexOf('passport-azure-oauth2') == -1)) { passport.push('passport-azure-oauth2'); passport.push('jwt-simple'); } - if ((typeof config.domains[i].authstrategies.oidc == 'object') && (typeof config.domains[i].authstrategies.oidc.clientid == 'string') && (typeof config.domains[i].authstrategies.oidc.clientsecret == 'string') && (typeof config.domains[i].authstrategies.oidc.issuer == 'string') && (passport.indexOf('@mstrhakr/passport-openidconnect') == -1)) { - if ((nodeVersion >= 17) || ((Math.floor(nodeVersion) == 16) && (nodeVersion >= 16.13)) || ((Math.floor(nodeVersion) == 14) && (nodeVersion >= 14.15)) || ((Math.floor(nodeVersion) == 12) && (nodeVersion >= 12.19))) { passport.push('@mstrhakr/passport-openidconnect'); passport.push('openid-client'); } else { addServerWarning('This NodeJS version does not support OpenID.', 25); delete config.domains[i].authstrategies.oidc; } + if ((typeof config.domains[i].authstrategies.oidc == 'object') && (passport.indexOf('openid-client@5.7.1') == -1)) { + if ((nodeVersion >= 17) + || ((Math.floor(nodeVersion) == 16) && (nodeVersion >= 16.13)) + || ((Math.floor(nodeVersion) == 14) && (nodeVersion >= 14.15)) + || ((Math.floor(nodeVersion) == 12) && (nodeVersion >= 12.19))) { + passport.push('openid-client@5.7.1'); + } else { + addServerWarning('This NodeJS version does not support OpenID Connect on MeshCentral.', 25); + delete config.domains[i].authstrategies.oidc; + } } if ((typeof config.domains[i].authstrategies.saml == 'object') || (typeof config.domains[i].authstrategies.jumpcloud == 'object')) { passport.push('passport-saml'); } } if (config.domains[i].sessionrecording != null) { sessionRecording = true; } if ((config.domains[i].passwordrequirements != null) && (config.domains[i].passwordrequirements.bancommonpasswords == true)) { wildleek = true; } if ((config.domains[i].newaccountscaptcha != null) && (config.domains[i].newaccountscaptcha !== false)) { captcha = true; } + if ((typeof config.domains[i].duo2factor == 'object') && (passport.indexOf('@duosecurity/duo_universal') == -1)) { passport.push('@duosecurity/duo_universal'); } } // Build the list of required modules - var modules = ['ws@5.2.3', 'cbor@5.2.0', '@yetzt/nedb', 'https', 'yauzl', 'ipcheck', 'express', 'archiver@5.3.1', 'multiparty', 'node-forge', 'express-ws@4.0.0', 'compression', 'body-parser', 'cookie-session@1.4.0', 'express-handlebars']; - if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.4'); modules.push('loadavg-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules - if (ldap == true) { modules.push('ldapauth-fork'); } - if (ssh == true) { if (nodeVersion < 11) { addServerWarning('MeshCentral SSH support requires NodeJS 11 or higher.', 1); } else { modules.push('ssh2'); } } + // NOTE: ALL MODULES MUST HAVE A VERSION NUMBER AND THE VERSION MUST MATCH THAT USED IN Dockerfile + var modules = ['archiver@7.0.1', 'body-parser@1.20.3', 'cbor@5.2.0', 'compression@1.7.5', 'cookie-session@2.1.0', 'express@4.21.2', 'express-handlebars@7.1.3', 'express-ws@5.0.2', 'ipcheck@0.1.0', 'minimist@1.2.8', 'multiparty@4.2.3', '@seald-io/nedb', 'node-forge@1.3.1', 'ua-parser-js@1.0.39', 'ws@8.18.0', 'yauzl@2.10.0']; + if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.14'); modules.push('loadavg-windows@1.1.1'); if (sspi == true) { modules.push('node-sspi@0.2.10'); } } // Add Windows modules + if (ldap == true) { modules.push('ldapauth-fork@5.0.5'); } + if (ssh == true) { modules.push('ssh2@1.16.0'); } if (passport != null) { modules.push(...passport); } - if (captcha == true) { modules.push('svg-captcha'); } + if (captcha == true) { modules.push('svg-captcha@1.4.0'); } - if (sessionRecording == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file. + if (sessionRecording == true) { modules.push('image-size@1.1.1'); } // Need to get the remote desktop JPEG sizes to index the recodring file. if (config.letsencrypt != null) { modules.push('acme-client@4.2.5'); } // Add acme-client module. We need to force v4.2.4 or higher since olver versions using SHA-1 which is no longer supported by Let's Encrypt. if (config.settings.mqtt != null) { modules.push('aedes@0.39.0'); } // Add MQTT Modules - if (config.settings.mysql != null) { modules.push('mysql'); } // Add MySQL. - //if (config.settings.mysql != null) { modules.push('@mysql/xdevapi'); } // Add MySQL, official driver (https://dev.mysql.com/doc/dev/connector-nodejs/8.0/) - if (config.settings.mongodb != null) { modules.push('mongodb@4.9.1'); modules.push('saslprep'); } // Add MongoDB, official driver. - if (config.settings.postgres != null) { modules.push('pg@8.7.1'); modules.push('pgtools@0.3.2'); } // Add Postgres, Postgres driver. - if (config.settings.mariadb != null) { modules.push('mariadb'); } // Add MariaDB, official driver. - if (config.settings.acebase != null) { modules.push('acebase'); } // Add AceBase, official driver. - if (config.settings.sqlite3 != null) { modules.push('sqlite3'); } // Add sqlite3, official driver. - if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module. - if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks - if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support - else if (config.settings.xmongodb != null) { modules.push('mongojs'); } // Add MongoJS, old driver. - if (nodemailer || ((config.smtp != null) && (config.smtp.name != 'console')) || (config.sendmail != null)) { modules.push('nodemailer'); } // Add SMTP support + if (config.settings.mysql != null) { modules.push('mysql2@3.11.4'); } // Add MySQL. + //if (config.settings.mysql != null) { modules.push('@mysql/xdevapi@8.0.33'); } // Add MySQL, official driver (https://dev.mysql.com/doc/dev/connector-nodejs/8.0/) + if (config.settings.mongodb != null) { modules.push('mongodb@4.13.0'); modules.push('saslprep@1.0.3'); } // Add MongoDB, official driver. + if (config.settings.postgres != null) { modules.push('pg@8.13.1') } // Add Postgres, official driver. + if (config.settings.mariadb != null) { modules.push('mariadb@3.4.0'); } // Add MariaDB, official driver. + if (config.settings.acebase != null) { modules.push('acebase@1.29.5'); } // Add AceBase, official driver. + if (config.settings.sqlite3 != null) { modules.push('sqlite3@5.1.7'); } // Add sqlite3, official driver. + if (config.settings.vault != null) { modules.push('node-vault@0.10.2'); } // Add official HashiCorp's Vault module. + if (config.settings.plugins != null) { modules.push('semver@7.5.4'); } // Required for version compat testing and update checks + if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent@7.0.2'); } // Required for HTTP/HTTPS proxy support + else if (config.settings.xmongodb != null) { modules.push('mongojs@3.1.0'); } // Add MongoJS, old driver. + if (nodemailer || ((config.smtp != null) && (config.smtp.name != 'console')) || (config.sendmail != null)) { modules.push('nodemailer@6.9.16'); } // Add SMTP support if (sendgrid || (config.sendgrid != null)) { modules.push('@sendgrid/mail'); } // Add SendGrid support - if (args.translate) { modules.push('jsdom'); modules.push('esprima'); modules.push('minify-js'); modules.push('html-minifier'); } // Translation support - if (typeof config.settings.crowdsec == 'object') { modules.push('@crowdsec/express-bouncer'); } // Add CrowdSec bounser module (https://www.npmjs.com/package/@crowdsec/express-bouncer) + if ((args.translate || args.dev) && (Number(process.version.match(/^v(\d+\.\d+)/)[1]) >= 16)) { modules.push('jsdom@22.1.0'); modules.push('esprima@4.0.1'); modules.push('html-minifier@4.0.0'); } // Translation support + if (typeof config.settings.crowdsec == 'object') { modules.push('@crowdsec/express-bouncer@0.1.0'); } // Add CrowdSec bounser module (https://www.npmjs.com/package/@crowdsec/express-bouncer) + if (config.settings.prometheus != null) { modules.push('prom-client'); } // Add Prometheus Metrics support - // Setup encrypted zip support if needed - if (config.settings.autobackup && config.settings.autobackup.zippassword) { - modules.push('archiver-zip-encrypted'); + if (typeof config.settings.autobackup == 'object') { + // Setup encrypted zip support if needed + if (config.settings.autobackup.zippassword) { modules.push('archiver-zip-encrypted@2.0.0'); } // Enable Google Drive Support - if (typeof config.settings.autobackup.googledrive == 'object') { modules.push('googleapis'); } + if (typeof config.settings.autobackup.googledrive == 'object') { modules.push('googleapis@128.0.0'); } // Enable WebDAV Support if (typeof config.settings.autobackup.webdav == 'object') { - if ((typeof config.settings.autobackup.webdav.url != 'string') || (typeof config.settings.autobackup.webdav.username != 'string') || (typeof config.settings.autobackup.webdav.password != 'string')) { addServerWarning("Missing WebDAV parameters.", 2, null, !args.launch); } else { modules.push('webdav'); } + if ((typeof config.settings.autobackup.webdav.url != 'string') || (typeof config.settings.autobackup.webdav.username != 'string') || (typeof config.settings.autobackup.webdav.password != 'string')) { addServerWarning("Missing WebDAV parameters.", 2, null, !args.launch); } else { modules.push('webdav@4.11.4'); } } + // Enable S3 Support + if (typeof config.settings.autobackup.s3 == 'object') { modules.push('minio@8.0.2'); } } // Setup common password blocking @@ -4012,45 +4296,45 @@ function mainStart() { // Setup 2nd factor authentication if (config.settings.no2factorauth !== true) { // Setup YubiKey OTP if configured - if (yubikey == true) { modules.push('yubikeyotp'); } // Add YubiKey OTP support + if (yubikey == true) { modules.push('yubikeyotp@0.2.0'); } // Add YubiKey OTP support if (allsspi == false) { modules.push('otplib@10.2.3'); } // Google Authenticator support (v10 supports older NodeJS versions). } // Desktop multiplexor support - if (config.settings.desktopmultiplex === true) { modules.push('image-size'); } + if (config.settings.desktopmultiplex === true) { modules.push('image-size@1.1.1'); } // SMS support if (config.sms != null) { - if (config.sms.provider == 'twilio') { modules.push('twilio'); } - if (config.sms.provider == 'plivo') { modules.push('plivo'); } - if (config.sms.provider == 'telnyx') { modules.push('telnyx'); } + if (config.sms.provider == 'twilio') { modules.push('twilio@4.19.0'); } + if (config.sms.provider == 'plivo') { modules.push('plivo@4.58.0'); } + if (config.sms.provider == 'telnyx') { modules.push('telnyx@1.25.5'); } } // Messaging support if (config.messaging != null) { - if (config.messaging.telegram != null) { modules.push('telegram'); modules.push('input'); } + if (config.messaging.telegram != null) { modules.push('telegram@2.19.8'); modules.push('input@1.0.1'); } if (config.messaging.discord != null) { if (nodeVersion >= 17) { modules.push('discord.js@14.6.0'); } else { delete config.messaging.discord; addServerWarning('This NodeJS version does not support Discord.js.', 26); } } - if (config.messaging.xmpp != null) { modules.push('@xmpp/client'); } - if (config.messaging.pushover != null) { modules.push('node-pushover'); } - if (config.messaging.zulip != null) { modules.push('zulip'); } + if (config.messaging.xmpp != null) { modules.push('@xmpp/client@0.13.1'); } + if (config.messaging.pushover != null) { modules.push('node-pushover@1.0.0'); } + if (config.messaging.zulip != null) { modules.push('zulip@0.1.0'); } } // Setup web based push notifications - if ((typeof config.settings.webpush == 'object') && (typeof config.settings.webpush.email == 'string')) { modules.push('web-push'); } + if ((typeof config.settings.webpush == 'object') && (typeof config.settings.webpush.email == 'string')) { modules.push('web-push@3.6.6'); } // Firebase Support - if (config.firebase != null) { modules.push('node-xcs'); } + if ((config.firebase != null) && (typeof config.firebase.serviceaccountfile == 'string')) { modules.push('firebase-admin@12.7.0'); } // Syslog support - if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog'); } - if (config.settings.syslogtcp) { modules.push('syslog'); } + if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog@1.2.0'); } + if (config.settings.syslogtcp) { modules.push('syslog@0.1.1-1'); } // Setup heapdump support if needed, useful for memory leak debugging // https://www.arbazsiddiqui.me/a-practical-guide-to-memory-leaks-in-nodejs/ - if (config.settings.heapdump === true) { modules.push('heapdump'); } + if (config.settings.heapdump === true) { modules.push('heapdump@0.3.15'); } // Install any missing modules and launch the server - InstallModules(modules, function () { + InstallModules(modules, args, function () { if (require('os').platform() == 'win32') { try { require('node-windows'); } catch (ex) { console.log("Module node-windows can't be loaded. Restart MeshCentral."); process.exit(); return; } } meshserver = CreateMeshCentralServer(config, args); meshserver.Start(); diff --git a/meshctrl.js b/meshctrl.js index 33a5b6f1..af4f1626 100644 --- a/meshctrl.js +++ b/meshctrl.js @@ -16,7 +16,7 @@ var settings = {}; const crypto = require('crypto'); const args = require('minimist')(process.argv.slice(2)); const path = require('path'); -const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'listevents', 'logintokens', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'editdevice', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower', 'indexagenterrorlog', 'agentdownload']; +const possibleCommands = ['edituser', 'listusers', 'listusersessions', 'listdevicegroups', 'listdevices', 'listusersofdevicegroup', 'listevents', 'logintokens', 'serverinfo', 'userinfo', 'adduser', 'removeuser', 'adddevicegroup', 'removedevicegroup', 'editdevicegroup', 'broadcast', 'showevents', 'addusertodevicegroup', 'removeuserfromdevicegroup', 'addusertodevice', 'removeuserfromdevice', 'sendinviteemail', 'generateinvitelink', 'config', 'movetodevicegroup', 'deviceinfo', 'removedevice', 'editdevice', 'addlocaldevice', 'addamtdevice', 'addusergroup', 'listusergroups', 'removeusergroup', 'runcommand', 'shell', 'upload', 'download', 'deviceopenurl', 'devicemessage', 'devicetoast', 'addtousergroup', 'removefromusergroup', 'removeallusersfromusergroup', 'devicesharing', 'devicepower', 'indexagenterrorlog', 'agentdownload', 'report', 'grouptoast', 'groupmessage', 'webrelay']; if (args.proxy != null) { try { require('https-proxy-agent'); } catch (ex) { console.log('Missing module "https-proxy-agent", type "npm install https-proxy-agent" to install it.'); return; } } if (args['_'].length == 0) { @@ -36,7 +36,10 @@ if (args['_'].length == 0) { console.log(" ListEvents - List server events."); console.log(" LoginTokens - List, create and remove login tokens."); console.log(" DeviceInfo - Show information about a device."); + console.log(" AddLocalDevice - Add a local device."); + console.log(" AddAmtDevice - Add a AMT device."); console.log(" EditDevice - Make changes to a device."); + console.log(" RemoveDevice - Delete a device."); console.log(" Config - Perform operation on config.json file."); console.log(" AddUser - Create a new user account."); console.log(" EditUser - Change a user account."); @@ -62,17 +65,21 @@ if (args['_'].length == 0) { console.log(" Shell - Access command shell of a remote device."); console.log(" Upload - Upload a file to a remote device."); console.log(" Download - Download a file from a remote device."); + console.log(" WebRelay - Creates a HTTP/HTTPS webrelay link for a remote device."); console.log(" DeviceOpenUrl - Open a URL on a remote device."); console.log(" DeviceMessage - Open a message box on a remote device."); console.log(" DeviceToast - Display a toast notification on a remote device."); + console.log(" GroupMessage - Open a message box on remote devices in a specific device group."); + console.log(" GroupToast - Display a toast notification on remote devices in a specific device group."); console.log(" DevicePower - Perform wake/sleep/reset/off operations on remote devices."); console.log(" DeviceSharing - View, add and remove sharing links for a given device."); console.log(" AgentDownload - Download an agent of a specific type for a device group."); + console.log(" Report - Create and show a CSV report."); console.log("\r\nSupported login arguments:"); console.log(" --url [wss://server] - Server url, wss://localhost:443 is default."); console.log(" - Use wss://localhost:443?key=xxx if login key is required."); console.log(" --loginuser [username] - Login username, admin is default."); - console.log(" --loginpass [password] - Login password."); + console.log(" --loginpass [password] - Login password OR Leave blank to enter password at prompt"); console.log(" --token [number] - 2nd factor authentication token."); console.log(" --loginkey [hex] - Server login key in hex."); console.log(" --loginkeyfile [file] - File containing server login key in hex."); @@ -97,21 +104,30 @@ if (args['_'].length == 0) { case 'listdevices': { ok = true; break; } case 'listevents': { ok = true; break; } case 'logintokens': { ok = true; break; } - case 'listusersofdevicegroup': { - if (args.id == null) { console.log(winRemoveSingleQuotes("Missing group id, use --id '[groupid]'")); } - else { ok = true; } - break; - } - case 'deviceinfo': { - if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); } - else { ok = true; } - break; - } + case 'listusersofdevicegroup': + case 'deviceinfo': + case 'removedevice': case 'editdevice': { if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); } else { ok = true; } break; } + case 'addlocaldevice': { + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); } + else if (args.devicename == null) { console.log(winRemoveSingleQuotes("Missing devicename, use --devicename [devicename]")); } + else if (args.hostname == null) { console.log(winRemoveSingleQuotes("Missing hostname, use --hostname [hostname]")); } + else { ok = true; } + break; + } + case 'addamtdevice': { + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); } + else if (args.devicename == null) { console.log(winRemoveSingleQuotes("Missing devicename, use --devicename [devicename]")); } + else if (args.hostname == null) { console.log(winRemoveSingleQuotes("Missing hostname, use --hostname [hostname]")); } + else if (args.user == null) { console.log(winRemoveSingleQuotes("Missing user, use --user [user]")); } + else if (args.pass == null) { console.log(winRemoveSingleQuotes("Missing pass, use --pass [pass]")); } + else { ok = true; } + break; + } case 'addusertodevicegroup': { if ((args.id == null) && (args.group == null)) { console.log(winRemoveSingleQuotes("Device group identifier missing, use --id '[groupid]' or --group [groupname]")); } else if (args.userid == null) { console.log("Add user to group missing useid, use --userid [userid]"); } @@ -208,7 +224,7 @@ if (args['_'].length == 0) { case 'sendinviteemail': { if ((args.id == null) && (args.group == null)) { console.log("Device group identifier missing, use --id '[groupid]' or --group [groupname]"); } else if (args.email == null) { console.log("Device email is missing, use --email [email]"); } - else { ok = true; } + else { ok = true; } break; } case 'generateinvitelink': { @@ -241,10 +257,9 @@ if (args['_'].length == 0) { } case 'agentdownload': { if (args.type == null) { console.log(winRemoveSingleQuotes("Missing device type, use --type [agenttype]")); } - var at = parseInt(args.type); - if ((at == null) || isNaN(at) || (at < 1) || (at > 11000)) { console.log(winRemoveSingleQuotes("Invalid agent type, must be a number.")); } - if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[meshid]'")); } - if ((typeof args.id != 'string') || (args.id.length != 64)) { console.log(winRemoveSingleQuotes("Invalid meshid.")); } + else if ((parseInt(args.type) == null) || isNaN(parseInt(args.type)) || (parseInt(args.type) < 1) || (parseInt(args.type) > 11000)) { console.log(winRemoveSingleQuotes("Invalid agent type, must be a number.")); } + else if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[meshid]'")); } + else if ((typeof args.id != 'string') || (args.id.length != 64)) { console.log(winRemoveSingleQuotes("Invalid meshid.")); } else { ok = true; } break; } @@ -263,6 +278,12 @@ if (args['_'].length == 0) { else { ok = true; } break; } + case 'webrelay': { + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); } + else if (args.type == null) { console.log(winRemoveSingleQuotes("Missing protocol type, use --type [http,https]")); } + else { ok = true; } + break; + } case 'deviceopenurl': { if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device id, use --id '[deviceid]'")); } else if (args.openurl == null) { console.log("Remote URL, use --openurl [url] specify the link to open."); } @@ -281,6 +302,23 @@ if (args['_'].length == 0) { else { ok = true; } break; } + case 'groupmessage': { + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device group id, use --id '[devicegroupid]'")); } + else if (args.msg == null) { console.log("Remote message, use --msg \"[message]\" specify a remote message."); } + else { ok = true; } + break; + } + case 'grouptoast': { + if (args.id == null) { console.log(winRemoveSingleQuotes("Missing device group id, use --id '[devicegroupid]'")); } + else if (args.msg == null) { console.log("Remote message, use --msg \"[message]\" specify a remote message."); } + else { ok = true; } + break; + } + case 'report': { + if (args.type == null) { console.log(winRemoveSingleQuotes("Missing report type, use --type '[reporttype]'")); } + else { ok = true; } + break; + } case 'help': { if (args['_'].length < 2) { console.log("Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands.join(', ') + '.'); @@ -304,7 +342,7 @@ if (args['_'].length == 0) { console.log(" --email [email] - Email address."); console.log("\r\nOptional arguments:\r\n"); console.log(" --name (name) - Name of recipient to be included in the email."); - console.log(" --message (msg) - Message to be included in the email."); + console.log(" --message (msg) - Message to be included in the email."); break; } case 'generateinvitelink': { @@ -470,7 +508,7 @@ if (args['_'].length == 0) { console.log(" --realname [name] - Set the real name for this account."); console.log(" --phone [number] - Set the account phone number."); console.log(" --rights [none|full|a,b,c] - Comma separated list of server permissions. Possible values:"); - console.log(" manageusers,backup,restore,update,fileaccess,locked,nonewgroups,notools,usergroups,recordings,locksettings,allevents"); + console.log(" manageusers,serverbackup,serverrestore,serverupdate,fileaccess,locked,nonewgroups,notools,usergroups,recordings,locksettings,allevents,nonewdevices"); break; } case 'edituser': { @@ -487,7 +525,7 @@ if (args['_'].length == 0) { console.log(" --realname [name] - Set the real name for this account."); console.log(" --phone [number] - Set the account phone number."); console.log(" --rights [none|full|a,b,c] - Comma separated list of server permissions. Possible values:"); - console.log(" manageusers,backup,restore,update,fileaccess,locked,nonewgroups,notools,usergroups,recordings,locksettings,allevents"); + console.log(" manageusers,serverbackup,serverrestore,serverupdate,fileaccess,locked,nonewgroups,notools,usergroups,recordings,locksettings,allevents,nonewdevices"); break; } case 'removeuser': { @@ -764,6 +802,66 @@ if (args['_'].length == 0) { console.log(" --json - Give results in JSON format."); break; } + case 'removedevice': { + console.log("Delete a device, Example usages:\r\n"); + console.log(winRemoveSingleQuotes(" MeshCtrl RemoveDevice --id 'deviceid'")); + console.log("\r\nRequired arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --id [deviceid] - The device identifier."); + } else { + console.log(" --id '[deviceid]' - The device identifier."); + } + break; + } + case 'addlocaldevice': { + console.log("Add a Local Device, Example usages:\r\n"); + console.log(winRemoveSingleQuotes(" MeshCtrl AddLocalDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname'")); + console.log(winRemoveSingleQuotes(" MeshCtrl AddLocalDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname' --type 6")); + console.log("\r\nRequired arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --id [meshid] - The mesh identifier."); + console.log(" --devicename [devicename] - The device name."); + console.log(" --hostname [hostname] - The devices hostname or ip address."); + } else { + console.log(" --id '[meshid]' - The mesh identifier."); + console.log(" --devicename '[devicename]' - The device name."); + console.log(" --hostname '[hostname]' - The devices hostname or ip address."); + } + + console.log("\r\nOptional arguments:\r\n"); + console.log(" --type [TypeNumber] - With the following choices:"); + console.log(" type 4 - Default, Windows (RDP)"); + console.log(" type 6 - Linux (SSH/SCP/VNC)"); + console.log(" type 29 - macOS (SSH/SCP/VNC)"); + break; + } + case 'addamtdevice': { + console.log("Add an Intel AMT Device, Example usages:\r\n"); + console.log(winRemoveSingleQuotes(" MeshCtrl AddAmtDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname --user 'admin' --pass 'admin'")); + console.log(winRemoveSingleQuotes(" MeshCtrl AddAmtDevice --id 'meshid' --devicename 'devicename' --hostname 'hostname --user 'admin' --pass 'admin' --notls")); + console.log("\r\nRequired arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --id [meshid] - The mesh identifier."); + console.log(" --devicename [devicename] - The device name."); + console.log(" --hostname [hostname] - The devices hostname or ip address."); + console.log(" --user [user] - The devices AMT username."); + console.log(" --pass [pass] - The devices AMT password."); + console.log("") + } else { + console.log(" --id '[meshid]' - The mesh identifier."); + console.log(" --devicename '[devicename]' - The device name."); + console.log(" --hostname '[hostname]' - The devices hostname or ip address."); + console.log(" --user '[user]' - The devices AMT username."); + console.log(" --pass '[pass]' - The devices AMT password."); + } + console.log("\r\nOptional arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --notls - Use No TLS Security."); + } else { + console.log(" --notls - Use No TLS Security."); + } + break; + } case 'editdevice': { console.log("Change information about a device, Example usages:\r\n"); console.log(winRemoveSingleQuotes(" MeshCtrl EditDevice --id 'deviceid' --name 'device1'")); @@ -795,6 +893,7 @@ if (args['_'].length == 0) { console.log("Run a shell command on a remote device, Example usages:\r\n"); console.log(winRemoveSingleQuotes(" MeshCtrl RunCommand --id 'deviceid' --run \"command\"")); console.log(winRemoveSingleQuotes(" MeshCtrl RunCommand --id 'deviceid' --run \"command\" --powershell")); + console.log(winRemoveSingleQuotes(" MeshCtrl RunCommand --id 'deviceid' --run \"command\" --reply")); console.log("\r\nRequired arguments:\r\n"); if (process.platform == 'win32') { console.log(" --id [deviceid] - The device identifier."); @@ -806,6 +905,7 @@ if (args['_'].length == 0) { console.log(" --powershell - Run in Windows PowerShell."); console.log(" --runasuser - Attempt to run the command as logged in user."); console.log(" --runasuseronly - Only run the command as the logged in user."); + console.log(" --reply - Return with the output from running the command."); break; } case 'shell': { @@ -854,6 +954,7 @@ if (args['_'].length == 0) { console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --start " + localISOTime + " --duration 30")); console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --start " + localISOTime + " --duration 30 --daily")); console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --type desktop,terminal --consent prompt")); + console.log(winRemoveSingleQuotes(" MeshCtrl DeviceSharing --id 'deviceid' --add Guest --type http --port 80")); console.log("\r\nRequired arguments:\r\n"); if (process.platform == 'win32') { console.log(" --id [deviceid] - The device identifier."); @@ -861,21 +962,23 @@ if (args['_'].length == 0) { console.log(" --id '[deviceid]' - The device identifier."); } console.log("\r\nOptional arguments:\r\n"); - console.log(" --remove [shareid] - Remove a device sharing link."); - console.log(" --add [guestname] - Add a device sharing link."); - console.log(" --type [desktop,terminal,files] - Type of sharing to add, can be combined. default is desktop."); - console.log(" --viewonly - Make desktop sharing view only."); - console.log(" --consent [notify,prompt] - Consent flags, default is notify."); - console.log(" --start [yyyy-mm-ddThh:mm:ss] - Start time, default is now."); - console.log(" --end [yyyy-mm-ddThh:mm:ss] - End time."); - console.log(" --duration [minutes] - Duration of the share, default is 60 minutes."); - console.log(" --daily - Add recurring daily device share."); - console.log(" --weekly - Add recurring weekly device share."); + console.log(" --remove [shareid] - Remove a device sharing link."); + console.log(" --add [guestname] - Add a device sharing link."); + console.log(" --type [desktop,terminal,files,http,https] - Type of sharing to add, can be combined. default is desktop."); + console.log(" --viewonly - Make desktop sharing view only."); + console.log(" --consent [notify,prompt,none] - Consent flags, default is notify."); + console.log(" --start [yyyy-mm-ddThh:mm:ss] - Start time, default is now."); + console.log(" --end [yyyy-mm-ddThh:mm:ss] - End time."); + console.log(" --duration [minutes] - Duration of the share, default is 60 minutes."); + console.log(" --daily - Add recurring daily device share."); + console.log(" --weekly - Add recurring weekly device share."); + console.log(" --port [portnumber] - Set alternative port for http or https, default is 80 for http and 443 for https."); break; } case 'agentdownload': { console.log("Download an agent of a specific type for a given device group, Example usages:\r\n"); console.log(winRemoveSingleQuotes(" MeshCtrl AgentDownload --id 'groupid' --type 3")); + console.log(winRemoveSingleQuotes(" MeshCtrl AgentDownload --id 'groupid' --type 3 --installflags 1")); console.log("\r\nRequired arguments:\r\n"); console.log(" --type [ArchitectureNumber] - Agent architecture number."); if (process.platform == 'win32') { @@ -883,6 +986,11 @@ if (args['_'].length == 0) { } else { console.log(" --id '[groupid]' - The device group identifier."); } + console.log("\r\nOptional arguments:\r\n"); + console.log(" --installflags [InstallFlagsNumber] - With the following choices:"); + console.log(" installflags 0 - Default, Interactive & Background, offers connect button & install/uninstall"); + console.log(" installflags 1 - Interactive only, offers only connect button, not install/uninstall"); + console.log(" installflags 2 - Background only, offers only install/uninstall, not connect"); break; } case 'upload': { @@ -914,6 +1022,21 @@ if (args['_'].length == 0) { console.log(" --target [localpath] - The local path to download the file to."); break; } + case 'webrelay': { + console.log("Generate a webrelay URL to access a HTTP/HTTPS service on a remote device, Example usages:\r\n"); + console.log(winRemoveSingleQuotes(" MeshCtrl WebRelay --id 'deviceid' --type http --port 80")); + console.log(winRemoveSingleQuotes(" MeshCtrl WebRelay --id 'deviceid' --type https --port 443")); + console.log("\r\nRequired arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --id [deviceid] - The device identifier."); + } else { + console.log(" --id '[deviceid]' - The device identifier."); + } + console.log(" --type [http,https] - Type of relay from remote device, http or https."); + console.log("\r\nOptional arguments:\r\n"); + console.log(" --port [portnumber] - Set alternative port for http or https, default is 80 for http and 443 for https."); + break; + } case 'deviceopenurl': { console.log("Open a web page on a remote device, Example usages:\r\n"); console.log(winRemoveSingleQuotes(" MeshCtrl DeviceOpenUrl --id 'deviceid' --openurl http://meshcentral.com")); @@ -930,15 +1053,17 @@ if (args['_'].length == 0) { console.log("Display a message on the remote device, Example usages:\r\n"); console.log(winRemoveSingleQuotes(" MeshCtrl DeviceMessage --id 'deviceid' --msg \"message\"")); console.log(winRemoveSingleQuotes(" MeshCtrl DeviceMessage --id 'deviceid' --msg \"message\" --title \"title\"")); + console.log(winRemoveSingleQuotes(" MeshCtrl DeviceMessage --id 'deviceid' --msg \"message\" --title \"title\" --timeout 120000")); console.log("\r\nRequired arguments:\r\n"); if (process.platform == 'win32') { - console.log(" --id [deviceid] - The device identifier."); + console.log(" --id [deviceid] - The device identifier."); } else { - console.log(" --id '[deviceid]' - The device identifier."); + console.log(" --id '[deviceid]' - The device identifier."); } - console.log(" --msg [message] - The message to display."); + console.log(" --msg [message] - The message to display."); console.log("\r\nOptional arguments:\r\n"); - console.log(" --title [title] - Messagebox title, default is \"MeshCentral\"."); + console.log(" --title [title] - Messagebox title, default is \"MeshCentral\"."); + console.log(" --timeout [miliseconds] - After timeout messagebox vanishes, 0 keeps messagebox open until closed manually, default is 120000 (2 Minutes)."); break; } case 'devicetoast': { @@ -956,6 +1081,52 @@ if (args['_'].length == 0) { console.log(" --title [title] - Toast title, default is \"MeshCentral\"."); break; } + case 'groupmessage': { + console.log("Open a message box on remote devices in a specific device group, Example usages:\r\n"); + console.log(winRemoveSingleQuotes(" MeshCtrl GroupMessage --id 'devicegroupid' --msg \"message\"")); + console.log(winRemoveSingleQuotes(" MeshCtrl GroupMessage --id 'devicegroupid' --msg \"message\" --title \"title\"")); + console.log(winRemoveSingleQuotes(" MeshCtrl GroupMessage --id 'devicegroupid' --msg \"message\" --title \"title\" --timeout 120000")); + console.log("\r\nRequired arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --id [devicegroupid] - The device identifier."); + } else { + console.log(" --id '[devicegroupid]' - The device identifier."); + } + console.log(" --msg [message] - The message to display."); + console.log("\r\nOptional arguments:\r\n"); + console.log(" --title [title] - Messagebox title, default is \"MeshCentral\"."); + console.log(" --timeout [miliseconds] - After timeout messagebox vanishes, 0 keeps messagebox open until closed manually, default is 120000 (2 Minutes)."); + break; + } + case 'grouptoast': { + console.log("Display a toast notification on remote devices in a specific device group, Example usages:\r\n"); + console.log(winRemoveSingleQuotes(" MeshCtrl GroupToast --id 'devicegroupid' --msg \"message\"")); + console.log(winRemoveSingleQuotes(" MeshCtrl GroupToast --id 'devicegroupid' --msg \"message\" --title \"title\"")); + console.log("\r\nRequired arguments:\r\n"); + if (process.platform == 'win32') { + console.log(" --id [devicegroupid] - The device identifier."); + } else { + console.log(" --id '[devicegroupid]' - The device identifier."); + } + console.log(" --msg [message] - The message to display."); + console.log("\r\nOptional arguments:\r\n"); + console.log(" --title [title] - Toast title, default is \"MeshCentral\"."); + break; + } + case 'report': { + console.log("Generate a CSV report, Example usages:\r\n"); + console.log(" MeshCtrl Report --type sessions --devicegroup mesh//..."); + console.log(" MeshCtrl Report --type traffic --json"); + console.log(" MeshCtrl Report --type logins --groupby day"); + console.log(" MeshCtrl Report --type db"); + console.log("\r\nOptional arguments:\r\n"); + console.log(" --start [yyyy-mm-ddThh:mm:ss] - Filter the results starting at that date. Defaults to last 24h and last week when used with --groupby day. Usable with sessions, traffic and logins"); + console.log(" --end [yyyy-mm-ddThh:mm:ss] - Filter the results ending at that date. Defaults to now. Usable with sessions, traffic and logins"); + console.log(" --groupby [name] - How to group results. Options: user, day, device. Defaults to user. User and day usable in sessions and logins, device usable in sessions."); + console.log(" --devicegroup [devicegroupid] - Filter the results by device group. Usable in sessions"); + console.log(" --showtraffic - Add traffic data in sessions report"); + break; + } default: { console.log("Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands.join(', ') + '.'); } @@ -965,7 +1136,46 @@ if (args['_'].length == 0) { } } - if (ok) { serverConnect(); } + if (ok) { + if(args.loginpass===true){ + const readline = require('readline'); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: false + }); + process.stdout.write('Enter your password: '); + const stdin = process.openStdin(); + stdin.setRawMode(true); // Set raw mode to prevent echoing of characters + stdin.resume(); + args.loginpass = ''; + process.stdin.on('data', (char) => { + char = char + ''; + switch (char) { + case '\n': + case '\r': + case '\u0004': // They've finished entering their password + stdin.setRawMode(false); + stdin.pause(); + process.stdout.clearLine(); process.stdout.cursorTo(0); + rl.close(); + serverConnect(); + break; + case '\u0003': // Ctrl+C + process.stdout.write('\n'); + process.exit(); + break; + default: // Mask the password with "*" + args.loginpass += char; + process.stdout.clearLine(); process.stdout.cursorTo(0); + process.stdout.write('Enter your password: ' + '*'.repeat(args.loginpass.length)); + break; + } + }); + }else{ + serverConnect(); + } + } } function displayConfigHelp() { @@ -986,8 +1196,8 @@ function displayConfigHelp() { function performConfigOperations(args) { var domainValues = ['title', 'title2', 'titlepicture', 'trustedcert', 'welcomepicture', 'welcometext', 'userquota', 'meshquota', 'newaccounts', 'usernameisemail', 'newaccountemaildomains', 'newaccountspass', 'newaccountsrights', 'geolocation', 'lockagentdownload', 'userconsentflags', 'Usersessionidletimeout', 'auth', 'ldapoptions', 'ldapusername', 'ldapuserbinarykey', 'ldapuseremail', 'footer', 'certurl', 'loginKey', 'userallowedip', 'agentallowedip', 'agentnoproxy', 'agentconfig', 'orphanagentuser', 'httpheaders', 'yubikey', 'passwordrequirements', 'limits', 'amtacmactivation', 'redirects', 'sessionrecording', 'hide']; - var domainObjectValues = [ 'ldapoptions', 'httpheaders', 'yubikey', 'passwordrequirements', 'limits', 'amtacmactivation', 'redirects', 'sessionrecording' ]; - var domainArrayValues = [ 'newaccountemaildomains', 'newaccountsrights', 'loginkey', 'agentconfig' ]; + var domainObjectValues = ['ldapoptions', 'httpheaders', 'yubikey', 'passwordrequirements', 'limits', 'amtacmactivation', 'redirects', 'sessionrecording']; + var domainArrayValues = ['newaccountemaildomains', 'newaccountsrights', 'loginkey', 'agentconfig']; var configChange = false; var fs = require('fs'); var path = require('path'); @@ -1001,7 +1211,7 @@ function performConfigOperations(args) { if (fs.existsSync(configFile) == false) { console.log("Unable to find config.json."); return; } var config = null; try { config = fs.readFileSync(configFile).toString('utf8'); } catch (ex) { console.log("Error: Unable to read config.json"); return; } - try { config = require(configFile); } catch (e) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; } + try { config = JSON.parse(fs.readFileSync(configFile)); } catch (e) { console.log('ERROR: Unable to parse ' + configFile + '.'); return null; } if (args.adddomain != null) { didSomething++; if (config.domains == null) { config.domains = {}; } @@ -1149,10 +1359,10 @@ function serverConnect() { var domainid = '', username = 'admin'; if (args.logindomain != null) { domainid = args.logindomain; } if (args.loginuser != null) { username = args.loginuser; } - url += '?auth=' + encodeCookie({ userid: 'user/' + domainid + '/' + username, domainid: domainid }, ckey); + url += (url.indexOf('?key=') >= 0 ? '&auth=' : '?auth=') + encodeCookie({ userid: 'user/' + domainid + '/' + username, domainid: domainid }, ckey); } else { if (args.logindomain != null) { console.log("--logindomain can only be used along with --loginkey."); process.exit(); return; } - if (loginCookie != null) { url += '?auth=' + loginCookie; } + if (loginCookie != null) { url += (url.indexOf('?key=') >= 0 ? '&auth=' : '?auth=') + loginCookie; } } const ws = new WebSocket(url, options); @@ -1172,7 +1382,7 @@ function serverConnect() { case 'listdevices': { if (args.details) { // Get list of devices with lots of details - ws.send(JSON.stringify({ action: 'getDeviceDetails', type: (args.csv)?'csv':'json' })); + ws.send(JSON.stringify({ action: 'getDeviceDetails', type: (args.csv) ? 'csv' : 'json' })); } else if (args.group) { ws.send(JSON.stringify({ action: 'nodes', meshname: args.group, responseid: 'meshctrl' })); } else if (args.id) { @@ -1185,7 +1395,7 @@ function serverConnect() { } case 'listevents': { limit = null; - if (args.limit) { limit = parseInt(args.limit); } + if (args.limit) { limit = parseInt(args.limit); } if ((typeof limit != 'number') || (limit < 1)) { limit = null; } var cmd = null; @@ -1369,6 +1579,29 @@ function serverConnect() { ws.send(JSON.stringify(op)); break; } + case 'addamtdevice': { + var op = { action: 'addamtdevice', amttls: 1, responseid: 'meshctrl' }; + if (args.id) { op.meshid = args.id; } + if ((typeof args.devicename == 'string') && (args.devicename != '')) { op.devicename = args.devicename; } + if ((typeof args.hostname == 'string') && (args.hostname != '')) { op.hostname = args.hostname; } + if ((typeof args.user == 'string') && (args.user != '')) { op.amtusername = args.user; } + if ((typeof args.pass == 'string') && (args.pass != '')) { op.amtpassword = args.pass; } + if (args.notls) { op.amttls = 0; } + ws.send(JSON.stringify(op)); + break; + } + case 'addlocaldevice': { + var op = { action: 'addlocaldevice', type: 4, responseid: 'meshctrl' }; + if (args.id) { op.meshid = args.id; } + if ((typeof args.devicename == 'string') && (args.devicename != '')) { op.devicename = args.devicename; } + if ((typeof args.hostname == 'string') && (args.hostname != '')) { op.hostname = args.hostname; } + if (args.type) { + if ((typeof parseInt(args.type) != 'number') || isNaN(parseInt(args.type))) { console.log("Invalid type."); process.exit(1); return; } + op.type = args.type; + } + ws.send(JSON.stringify(op)); + break; + } case 'editdevicegroup': { var op = { action: 'editmesh', responseid: 'meshctrl' }; if (args.id) { op.meshid = args.id; } else if (args.group) { op.meshidname = args.group; } @@ -1395,7 +1628,7 @@ function serverConnect() { break; } case 'movetodevicegroup': { - var op = { action: 'changeDeviceMesh', responseid: 'meshctrl', nodeids: [ args.devid ] }; + var op = { action: 'changeDeviceMesh', responseid: 'meshctrl', nodeids: [args.devid] }; if (args.id) { op.meshid = args.id; } else if (args.group) { op.meshname = args.group; } ws.send(JSON.stringify(op)); break; @@ -1488,6 +1721,11 @@ function serverConnect() { ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: args.id, nodeinfo: true, responseid: 'meshctrl' })); break; } + case 'removedevice': { + var op = { action: 'removedevices', nodeids: [ args.id ], responseid: 'meshctrl' }; + ws.send(JSON.stringify(op)); + break; + } case 'editdevice': { var op = { action: 'changedevice', nodeid: args.id, responseid: 'meshctrl' }; if (typeof args.name == 'string') { op.name = args.name; } @@ -1502,7 +1740,9 @@ function serverConnect() { case 'runcommand': { var runAsUser = 0; if (args.runasuser) { runAsUser = 1; } else if (args.runasuseronly) { runAsUser = 2; } - ws.send(JSON.stringify({ action: 'runcommands', nodeids: [args.id], type: ((args.powershell) ? 2 : 0), cmds: args.run, responseid: 'meshctrl', runAsUser: runAsUser })); + var reply = false; + if (args.reply) { reply = true; } + ws.send(JSON.stringify({ action: 'runcommands', nodeids: [args.id], type: ((args.powershell) ? 2 : 0), cmds: args.run, responseid: 'meshctrl', runAsUser: runAsUser, reply: reply })); break; } case 'shell': @@ -1545,6 +1785,10 @@ function serverConnect() { var u = settings.xxurl.replace('wss://', 'https://').replace('/control.ashx', '/meshagents'); if (u.indexOf('?') > 0) { u += '&'; } else { u += '?'; } u += 'id=' + args.type + '&meshid=' + args.id; + if (args.installflags) { + if ((typeof parseInt(args.installflags) != 'number') || isNaN(parseInt(args.installflags)) || (parseInt(args.installflags) < 0) || (parseInt(args.installflags) > 2)) { console.log("Invalid Installflags."); process.exit(1); return; } + u += '&installflags=' + args.installflags; + } const options = { rejectUnauthorized: false, checkServerIdentity: onVerifyServer } const fs = require('fs'); const https = require('https'); @@ -1582,6 +1826,29 @@ function serverConnect() { req.end() break; } + case 'webrelay': { + var protocol = null; + if (args.type != null) { + if (args.type == 'http') { + protocol = 1; + } else if (args.type == 'https') { + protocol = 2; + } else { + console.log("Unknown protocol type: " + args.type); process.exit(1); + } + } + var port = null; + if (typeof args.port == 'number') { + if ((args.port < 1) || (args.port > 65535)) { console.log("Port number must be between 1 and 65535."); process.exit(1); } + port = args.port; + } else if (protocol == 1) { + port = 80; + } else if (protocol == 2) { + port = 443; + } + ws.send(JSON.stringify({ action: 'webrelay', nodeid: args.id, port: port, appid: protocol, responseid: 'meshctrl' })); + break; + } case 'devicesharing': { if (args.add) { if (args.add.length == 0) { console.log("Invalid guest name."); process.exit(1); } @@ -1590,10 +1857,12 @@ function serverConnect() { var p = 0; if (args.type != null) { var shareTypes = args.type.toLowerCase().split(','); - for (var i in shareTypes) { if ((shareTypes[i] != 'terminal') && (shareTypes[i] != 'desktop') && (shareTypes[i] != 'files')) { console.log("Unknown sharing type: " + shareTypes[i]); process.exit(1); } } + for (var i in shareTypes) { if ((shareTypes[i] != 'terminal') && (shareTypes[i] != 'desktop') && (shareTypes[i] != 'files') && (shareTypes[i] != 'http') && (shareTypes[i] != 'https')) { console.log("Unknown sharing type: " + shareTypes[i]); process.exit(1); } } if (shareTypes.indexOf('terminal') >= 0) { p |= 1; } if (shareTypes.indexOf('desktop') >= 0) { p |= 2; } if (shareTypes.indexOf('files') >= 0) { p |= 4; } + if (shareTypes.indexOf('http') >= 0) { p |= 8; } + if (shareTypes.indexOf('https') >= 0) { p |= 16; } } if (p == 0) { p = 2; } // Desktop @@ -1628,6 +1897,19 @@ function serverConnect() { } } + var port = null; + // Set Port Number if http or https + if ((p & 8) || (p & 16)) { + if (typeof args.port == 'number') { + if ((args.port < 1) || (args.port > 65535)) { console.log("Port number must be between 1 and 65535."); process.exit(1); } + port = args.port; + } else if ((p & 8)) { + port = 80; + } else if ((p & 16)) { + port = 443; + } + } + // Start and end time var start = null, end = null; if (args.start) { start = Math.floor(Date.parse(args.start) / 1000); end = start + (60 * 60); } @@ -1644,14 +1926,14 @@ function serverConnect() { if ((typeof args.duration != 'number') || (args.duration < 1)) { console.log("Invalid duration value."); process.exit(1); return; } // Recurring sharing - ws.send(JSON.stringify({ action: 'createDeviceShareLink', nodeid: args.id, guestname: args.add, p: p, consent: consent, start: start, expire: args.duration, recurring: recurring, viewOnly: viewOnly, responseid: 'meshctrl' })); + ws.send(JSON.stringify({ action: 'createDeviceShareLink', nodeid: args.id, guestname: args.add, p: p, consent: consent, start: start, expire: args.duration, recurring: recurring, viewOnly: viewOnly, port: port, responseid: 'meshctrl' })); } else { if ((start == null) && (end == null)) { // Unlimited sharing - ws.send(JSON.stringify({ action: 'createDeviceShareLink', nodeid: args.id, guestname: args.add, p: p, consent: consent, expire: 0, viewOnly: viewOnly, responseid: 'meshctrl' })); + ws.send(JSON.stringify({ action: 'createDeviceShareLink', nodeid: args.id, guestname: args.add, p: p, consent: consent, expire: 0, viewOnly: viewOnly, port: port, responseid: 'meshctrl' })); } else { // Time limited sharing - ws.send(JSON.stringify({ action: 'createDeviceShareLink', nodeid: args.id, guestname: args.add, p: p, consent: consent, start: start, end: end, viewOnly: viewOnly, responseid: 'meshctrl' })); + ws.send(JSON.stringify({ action: 'createDeviceShareLink', nodeid: args.id, guestname: args.add, p: p, consent: consent, start: start, end: end, viewOnly: viewOnly, port: port, responseid: 'meshctrl' })); } } } else if (args.remove) { @@ -1666,13 +1948,56 @@ function serverConnect() { break; } case 'devicemessage': { - ws.send(JSON.stringify({ action: 'msg', type: 'messagebox', nodeid: args.id, title: args.title ? args.title : "MeshCentral", msg: args.msg, responseid: 'meshctrl' })); + ws.send(JSON.stringify({ action: 'msg', type: 'messagebox', nodeid: args.id, title: args.title ? args.title : "MeshCentral", msg: args.msg, timeout: args.timeout ? args.timeout : 120000, responseid: 'meshctrl' })); break; } case 'devicetoast': { ws.send(JSON.stringify({ action: 'toast', nodeids: [args.id], title: args.title ? args.title : "MeshCentral", msg: args.msg, responseid: 'meshctrl' })); break; } + case 'groupmessage': { + ws.send(JSON.stringify({ action: 'nodes', meshid: args.id, responseid: 'meshctrl' })); + break; + } + case 'grouptoast': { + ws.send(JSON.stringify({ action: 'nodes', meshid: args.id, responseid: 'meshctrl' })); + break; + } + case 'report': { + var reporttype = 1; + switch(args.type) { + case 'traffic': + reporttype = 2; + break; + case 'logins': + reporttype = 3; + break; + case 'db': + reporttype = 4; + break; + } + + var reportgroupby = 1; + if(args.groupby){ + reportgroupby = args.groupby === 'device' ? 2 : args.groupby === 'day' ? 3: 1; + } + + var start = null, end = null; + if (args.start) { + start = Math.floor(Date.parse(args.start) / 1000); + } else { + start = reportgroupby === 3 ? Math.round(new Date().getTime() / 1000) - (168 * 3600) : Math.round(new Date().getTime() / 1000) - (24 * 3600); + } + if (args.end) { + end = Math.floor(Date.parse(args.end) / 1000); + } else { + end = Math.round(new Date().getTime() / 1000); + } + if (end <= start) { console.log("End time must be ahead of start time."); process.exit(1); return; } + + ws.send(JSON.stringify({ action: 'report', type: reporttype, groupBy: reportgroupby, devGroup: args.devicegroup || null, start, end, tz: Intl.DateTimeFormat().resolvedOptions().timeZone, tf: new Date().getTimezoneOffset(), showTraffic: args.hasOwnProperty('showtraffic'), l: 'en', responseid: 'meshctrl' })); + break; + } } }); @@ -1685,11 +2010,11 @@ function serverConnect() { var srights = args.rights.toLowerCase().split(','); if (srights.indexOf('full') != -1) { siteadmin = 0xFFFFFFFF; } if (srights.indexOf('none') != -1) { siteadmin = 0x00000000; } - if (srights.indexOf('backup') != -1) { siteadmin |= 0x00000001; } + if (srights.indexOf('backup') != -1 || srights.indexOf('serverbackup') != -1) { siteadmin |= 0x00000001; } if (srights.indexOf('manageusers') != -1) { siteadmin |= 0x00000002; } - if (srights.indexOf('restore') != -1) { siteadmin |= 0x00000004; } + if (srights.indexOf('restore') != -1 || srights.indexOf('serverrestore') != -1) { siteadmin |= 0x00000004; } if (srights.indexOf('fileaccess') != -1) { siteadmin |= 0x00000008; } - if (srights.indexOf('update') != -1) { siteadmin |= 0x00000010; } + if (srights.indexOf('update') != -1 || srights.indexOf('serverupdate') != -1) { siteadmin |= 0x00000010; } if (srights.indexOf('locked') != -1) { siteadmin |= 0x00000020; } if (srights.indexOf('nonewgroups') != -1) { siteadmin |= 0x00000040; } if (srights.indexOf('notools') != -1) { siteadmin |= 0x00000080; } @@ -1697,6 +2022,7 @@ function serverConnect() { if (srights.indexOf('recordings') != -1) { siteadmin |= 0x00000200; } if (srights.indexOf('locksettings') != -1) { siteadmin |= 0x00000400; } if (srights.indexOf('allevents') != -1) { siteadmin |= 0x00000800; } + if (srights.indexOf('nonewdevices') != -1) { siteadmin |= 0x00001000; } } if (args.siteadmin) { siteadmin = 0xFFFFFFFF; } @@ -1709,7 +2035,7 @@ function serverConnect() { return siteadmin; } - ws.on('close', function() { process.exit(); }); + ws.on('close', function () { process.exit(); }); ws.on('error', function (err) { if (err.code == 'ENOTFOUND') { console.log('Unable to resolve ' + url); } else if (err.code == 'ECONNREFUSED') { console.log('Unable to connect to ' + url); } @@ -1893,6 +2219,9 @@ function serverConnect() { case 'toast': // TOAST case 'adduser': // ADDUSER case 'edituser': // EDITUSER + case 'addamtdevice': // ADDAMTDEVICE + case 'addlocaldevice': // ADDLOCALDEVICE + case 'removedevices': // REMOVEDEVICE case 'changedevice': // EDITDEVICE case 'deleteuser': // REMOVEUSER case 'createmesh': // ADDDEVICEGROUP @@ -1914,6 +2243,7 @@ function serverConnect() { case 'removeDeviceShare': case 'userbroadcast': { // BROADCAST if ((settings.cmd == 'shell') || (settings.cmd == 'upload') || (settings.cmd == 'download')) return; + if ((data.type == 'runcommands') && (settings.cmd != 'runcommand')) return; if ((settings.multiresponse != null) && (settings.multiresponse > 1)) { settings.multiresponse--; break; } if (data.responseid == 'meshctrl') { if (data.meshid) { console.log(data.result, data.meshid); } @@ -1924,6 +2254,7 @@ function serverConnect() { break; } case 'createDeviceShareLink': + case 'webrelay': if (data.result == 'OK') { if (data.publicid) { console.log('ID: ' + data.publicid); } console.log('URL: ' + data.url); @@ -1959,11 +2290,11 @@ function serverConnect() { console.log(x); var mesh = [], user = [], node = []; if (data.ugroups[i].links != null) { for (var j in data.ugroups[i].links) { if (j.startsWith('mesh/')) { mesh.push(j); } if (j.startsWith('user/')) { user.push(j); } if (j.startsWith('node/')) { node.push(j); } } } - console.log(' Users:'); + console.log(' Users:'); if (user.length > 0) { for (var j in user) { console.log(' ' + user[j]); } } else { console.log(' (None)'); } - console.log(' Device Groups:'); + console.log(' Device Groups:'); if (mesh.length > 0) { for (var j in mesh) { console.log(' ' + mesh[j] + ', ' + data.ugroups[i].links[mesh[j]].rights); } } else { console.log(' (None)'); } - console.log(' Devices:'); + console.log(' Devices:'); if (node.length > 0) { for (var j in node) { console.log(' ' + node[j] + ', ' + data.ugroups[i].links[node[j]].rights); } } else { console.log(' (None)'); } } } @@ -2058,7 +2389,7 @@ function serverConnect() { if (args.filter != null) { for (var meshid in data.nodes) { for (var d in data.nodes[meshid]) { data.nodes[meshid][d].meshid = meshid; } - data.nodes[meshid] = parseSearchOrInput(data.nodes[meshid], args.filter.toLowerCase()); + data.nodes[meshid] = parseSearchOrInput(data.nodes[meshid], args.filter.toString().toLowerCase()); } } @@ -2086,7 +2417,7 @@ function serverConnect() { } else if (args.json) { // Return all devices in JSON format var nodes = []; - + for (var i in data.nodes) { const devicesInMesh = data.nodes[i]; for (var j in devicesInMesh) { @@ -2116,6 +2447,30 @@ function serverConnect() { } process.exit(); } + if ((settings.cmd == 'groupmessage') && (data.responseid == 'meshctrl')) { + if ((data.nodes != null)) { + for (var i in data.nodes) { + for (let index = 0; index < data.nodes[i].length; index++) { + const element = data.nodes[i][index]; + ws.send(JSON.stringify({ action: 'msg', type: 'messagebox', nodeid: element._id, title: args.title ? args.title : "MeshCentral", msg: args.msg, timeout: args.timeout ? args.timeout : 120000 })); + } + } + } + + setTimeout(function(){ console.log('ok'); process.exit(); }, 1000); + } + if ((settings.cmd == 'grouptoast') && (data.responseid == 'meshctrl')) { + if (data.nodes != null) { + for (var i in data.nodes) { + var nodes = []; + for (let index = 0; index < data.nodes[i].length; index++) { + const element = data.nodes[i][index]; + nodes.push(element._id); + } + ws.send(JSON.stringify({ action: 'toast', nodeids: nodes, title: args.title ? args.title : "MeshCentral", msg: args.msg, responseid: 'meshctrl' })); + } + } + } break; } case 'meshes': { // LISTDEVICEGROUPS @@ -2185,6 +2540,8 @@ function serverConnect() { if (data.cause == 'noauth') { if (data.msg == 'tokenrequired') { console.log('Authentication token required, use --token [number].'); + } else if (data.msg == 'nokey') { + console.log('URL key is invalid or missing, please specify ?key=xxx in url'); } else { if ((args.loginkeyfile != null) || (args.loginkey != null)) { console.log('Invalid login, check the login key and that this computer has the correct time.'); @@ -2238,6 +2595,15 @@ function serverConnect() { console.log(data.data); process.exit(); } + case 'report': { + console.log('group,' + data.data.columns.flatMap(c => c.id).join(',')); + Object.keys(data.data.groups).forEach(gk => { + data.data.groups[gk].entries.forEach(e => { + console.log(gk + ',' + Object.values(e).join(',')); + }); + }); + process.exit(); + } default: { break; } } //console.log('Data', data); @@ -2300,8 +2666,8 @@ function getDevicesThatMatchFilter(nodes, x) { } else if (tagSearch != null) { // Tag filter for (var d in nodes) { - if ((nodes[d].tags == null) && (tagSearch == '')) { r.push(d); } - else if (nodes[d].tags != null) { for (var j in nodes[d].tags) { if (nodes[d].tags[j].toLowerCase() == tagSearch) { r.push(d); break; } } } + if ((nodes[d].tags == null) && (tagSearch == '')) { r.push(nodes[d]); } + else if (nodes[d].tags != null) { for (var j in nodes[d].tags) { if (nodes[d].tags[j].toLowerCase() == tagSearch) { r.push(nodes[d]); break; } } } } } else if (agentTagSearch != null) { // Agent Tag filter @@ -2341,9 +2707,9 @@ function getDevicesThatMatchFilter(nodes, x) { var rs = x.split(/\s+/).join('|'), rx = new RegExp(rs); // In some cases (like +), this can throw an exception. for (var d in nodes) { //if (showRealNames) { - //if (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase())) { r.push(nodes[d]); } + //if (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase())) { r.push(nodes[d]); } //} else { - if (rx.test(nodes[d].name.toLowerCase())) { r.push(nodes[d]); } + if (rx.test(nodes[d].name.toLowerCase())) { r.push(nodes[d]); } //} } } catch (ex) { for (var d in nodes) { r.push(nodes[d]); } } @@ -2416,7 +2782,7 @@ function connectTunnel(url) { if ((cmd.action == 'uploadack') || (cmd.action == 'uploadstart')) { settings.inFlight--; if (settings.uploadFile == null) { if (settings.inFlight == 0) { process.exit(); } return; } // If the file is closed and there is no more in-flight data, exit. - var loops = (cmd.action == 'uploadstart')?16:1; // If this is the first data to be sent, hot start now. We are going to have 16 blocks of data in-flight. + var loops = (cmd.action == 'uploadstart') ? 16 : 1; // If this is the first data to be sent, hot start now. We are going to have 16 blocks of data in-flight. for (var i = 0; i < loops; i++) { if (settings.uploadFile == null) continue; var buf = Buffer.alloc(65565); @@ -2458,7 +2824,7 @@ function connectTunnel(url) { // node meshctrl download --id oL4Y6Eg0qjnpHFrp1AxfxnBPenbDGnDSkC@HSOnAheIyd51pKhqSCUgJZakzwfKl --file c:\temp\MC-8Languages.png --target c:\temp\bob.png settings.tunnelws.on('message', function (rawdata) { if (settings.tunnelwsstate == 1) { - if ((rawdata.length > 0) && (rawdata[0] != '{')) { + if ((rawdata.length > 0) && (rawdata.toString()[0] != '{')) { // This is binary data, this test is ok because 4 first bytes is a control value. if ((rawdata.length > 4) && (settings.downloadFile != null)) { settings.downloadSize += (rawdata.length - 4); require('fs').writeSync(settings.downloadFile, rawdata, 4, rawdata.length - 4); } if ((rawdata[3] & 1) != 0) { // Check end flag @@ -2539,7 +2905,7 @@ function displayDeviceInfo(sysinfo, lastconnect, network, nodes) { } } } - if (node == null) { + if ((sysinfo == null && lastconnect == null && network == null) || (node == null)) { console.log("Invalid device id"); process.exit(); return; } @@ -2592,7 +2958,7 @@ function displayDeviceInfo(sysinfo, lastconnect, network, nodes) { // MeshAgent if (node.agent) { var output = {}, outputCount = 0; - var agentsStr = ["Unknown", "Windows 32bit console", "Windows 64bit console", "Windows 32bit service", "Windows 64bit service", "Linux 32bit", "Linux 64bit", "MIPS", "XENx86", "Android ARM", "Linux ARM", "MacOS 32bit", "Android x86", "PogoPlug ARM", "Android APK", "Linux Poky x86-32bit", "MacOS 64bit", "ChromeOS", "Linux Poky x86-64bit", "Linux NoKVM x86-32bit", "Linux NoKVM x86-64bit", "Windows MinCore console", "Windows MinCore service", "NodeJS", "ARM-Linaro", "ARMv6l / ARMv7l", "ARMv8 64bit", "ARMv6l / ARMv7l / NoKVM", "Unknown", "Unknown", "FreeBSD x86-64"]; + var agentsStr = ["Unknown", "Windows 32bit console", "Windows 64bit console", "Windows 32bit service", "Windows 64bit service", "Linux 32bit", "Linux 64bit", "MIPS", "XENx86", "Android", "Linux ARM", "macOS x86-32bit", "Android x86", "PogoPlug ARM", "Android", "Linux Poky x86-32bit", "macOS x86-64bit", "ChromeOS", "Linux Poky x86-64bit", "Linux NoKVM x86-32bit", "Linux NoKVM x86-64bit", "Windows MinCore console", "Windows MinCore service", "NodeJS", "ARM-Linaro", "ARMv6l / ARMv7l", "ARMv8 64bit", "ARMv6l / ARMv7l / NoKVM", "MIPS24KC (OpenWRT)", "Apple Silicon", "FreeBSD x86-64", "Unknown", "Linux ARM 64 bit (glibc/2.24 NOKVM)", "Alpine Linux x86 64 Bit (MUSL)", "Assistant (Windows)", "Armada370 - ARM32/HF (libc/2.26)", "OpenWRT x86-64", "OpenBSD x86-64", "Unknown", "Unknown", "MIPSEL24KC (OpenWRT)", "ARMADA/CORTEX-A53/MUSL (OpenWRT)", "Windows ARM 64bit console", "Windows ARM 64bit service"]; if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) { var str = ''; if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; } diff --git a/meshdesktopmultiplex.js b/meshdesktopmultiplex.js index 80bcad27..9b6d1e19 100644 --- a/meshdesktopmultiplex.js +++ b/meshdesktopmultiplex.js @@ -342,7 +342,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, id, func) { parent.parent.fs.close(fd); // Now that the recording file is closed, check if we need to index this file. - if (domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', filename); } + if (domain.sessionrecording.index && domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', filename); } // Add a event entry about this recording var basefile = parent.parent.path.basename(filename); @@ -847,7 +847,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, id, func) { return; } // Write the recording file header - parent.parent.debug('relay', 'Relay: Started recoding to file: ' + recFullFilename); + parent.parent.debug('relay', 'Relay: Started recording to file: ' + recFullFilename); var metadata = { magic: 'MeshCentralRelaySession', ver: 1, nodeid: obj.nodeid, meshid: obj.meshid, time: new Date().toLocaleString(), protocol: 2, devicename: obj.name, devicegroup: obj.meshname }; var firstBlock = JSON.stringify(metadata); recordingEntry(fd, 1, 0, firstBlock, function () { @@ -1347,6 +1347,8 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) { if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; } if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; } if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; } + if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; } + if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; } } if (typeof domain.notificationmessages == 'object') { if (typeof domain.notificationmessages.title == 'string') { command.soptions.notifyTitle = domain.notificationmessages.title; } @@ -1436,4 +1438,4 @@ a given size and timestamp. When looking at network traffic the flags are import - If traffic has the first (0x0001) flag set, the data is binary otherwise it's a string. - If the traffic has the second (0x0002) flag set, traffic is coming from the user's browser, if not, it's coming from the MeshAgent. -*/ \ No newline at end of file +*/ diff --git a/meshmail.js b/meshmail.js index 29368550..c5977ea1 100644 --- a/meshmail.js +++ b/meshmail.js @@ -26,6 +26,7 @@ module.exports.CreateMeshMail = function (parent, domain) { obj.mailCookieEncryptionKey = null; obj.verifyemail = false; obj.domain = domain; + obj.emailDelay = 5 * 60 * 1000; // Default of 5 minute email delay. //obj.mailTemplates = {}; const sortCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }) const constants = (obj.parent.crypto.constants ? obj.parent.crypto.constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead. @@ -41,8 +42,10 @@ module.exports.CreateMeshMail = function (parent, domain) { obj.sendGridServer = require('@sendgrid/mail'); obj.sendGridServer.setApiKey(obj.config.sendgrid.apikey); if (obj.config.sendgrid.verifyemail == true) { obj.verifyemail = true; } + if ((typeof obj.config.sendgrid.emaildelayseconds == 'number') && (obj.config.sendgrid.emaildelayseconds > 0)) { obj.emailDelay = obj.config.sendgrid.emaildelayseconds * 1000; } } else if (obj.config.smtp != null) { // Setup SMTP mail server + if ((typeof obj.config.smtp.emaildelayseconds == 'number') && (obj.config.smtp.emaildelayseconds > 0)) { obj.emailDelay = obj.config.smtp.emaildelayseconds * 1000; } if (obj.config.smtp.name == 'console') { // This is for debugging, the mails will be displayed on the console obj.smtpServer = 'console'; @@ -70,6 +73,7 @@ module.exports.CreateMeshMail = function (parent, domain) { } } else if (obj.config.sendmail != null) { // Setup Sendmail + if ((typeof obj.config.sendmail.emaildelayseconds == 'number') && (obj.config.sendmail.emaildelayseconds > 0)) { obj.emailDelay = obj.config.sendmail.emaildelayseconds * 1000; } const nodemailer = require('nodemailer'); var options = { sendmail: true }; if (typeof obj.config.sendmail.newline == 'string') { options.newline = obj.config.sendmail.newline; } @@ -571,7 +575,7 @@ module.exports.CreateMeshMail = function (parent, domain) { } // - // Device connetion and disconnection notifications + // Device connection and disconnection notifications // obj.deviceNotifications = {}; // UserId --> { timer, nodes: nodeid --> connectType } @@ -584,7 +588,7 @@ module.exports.CreateMeshMail = function (parent, domain) { // Add the user and start a timer if (obj.deviceNotifications[user._id] == null) { obj.deviceNotifications[user._id] = { nodes: {} }; - obj.deviceNotifications[user._id].timer = setTimeout(function () { sendDeviceNotifications(user._id); }, 5 * 60 * 1000); // 5 minute before email is sent + obj.deviceNotifications[user._id].timer = setTimeout(function () { sendDeviceNotifications(user._id); }, obj.emailDelay); } // Add the device @@ -648,7 +652,7 @@ module.exports.CreateMeshMail = function (parent, domain) { // Add the user and start a timer if (obj.deviceNotifications[user._id] == null) { obj.deviceNotifications[user._id] = { nodes: {} }; - obj.deviceNotifications[user._id].timer = setTimeout(function () { sendDeviceNotifications(user._id); }, 5 * 60 * 1000); // 5 minute before email is sent + obj.deviceNotifications[user._id].timer = setTimeout(function () { sendDeviceNotifications(user._id); }, obj.emailDelay); } // Add the device diff --git a/meshmessaging.js b/meshmessaging.js index 3be55582..646ae4a2 100644 --- a/meshmessaging.js +++ b/meshmessaging.js @@ -107,13 +107,20 @@ } } +// For Slack Webhook +{ + "messaging": { + "slack": true + } +} + */ // Construct a messaging server object module.exports.CreateServer = function (parent) { var obj = {}; obj.parent = parent; - obj.providers = 0; // 1 = Telegram, 2 = Signal, 4 = Discord, 8 = XMPP, 16 = CallMeBot, 32 = Pushover, 64 = ntfy, 128 = Zulip + obj.providers = 0; // 1 = Telegram, 2 = Signal, 4 = Discord, 8 = XMPP, 16 = CallMeBot, 32 = Pushover, 64 = ntfy, 128 = Zulip, 256 = Slack obj.telegramClient = null; obj.discordClient = null; obj.discordUrl = null; @@ -122,6 +129,8 @@ module.exports.CreateServer = function (parent) { obj.callMeBotClient = null; obj.pushoverClient = null; obj.zulipClient = null; + obj.slackClient = null; + const sortCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }) // Telegram client setup if (parent.config.messaging.telegram) { @@ -244,7 +253,7 @@ module.exports.CreateServer = function (parent) { } // Pushover client setup (https://pushover.net) - if (parent.config.messaging.pushover) { + if (typeof parent.config.messaging.pushover == 'object') { // Validate Pushover configuration values var pushoverOK = true; if (typeof parent.config.messaging.pushover.token != 'string') { console.log('Invalid or missing Pushover token.'); pushoverOK = false; } @@ -269,6 +278,12 @@ module.exports.CreateServer = function (parent) { obj.providers += 128; // Enable zulip messaging } + // Slack Webhook setup (https://slack.com) + if (parent.config.messaging.slack) { + obj.slackClient = true; + obj.providers += 256; // Enable slack messaging + } + // Send a direct message to a specific userid async function discordSendMsg(userId, message) { const user = await obj.discordClient.users.fetch(userId).catch(function () { return null; }); @@ -285,7 +300,7 @@ module.exports.CreateServer = function (parent) { var guild = await value.fetch(); const guildMembers = await guild.members.search({ query: username }); guildMembers.forEach(async function (value, key) { - if ((value.user.username + '#' + value.user.discriminator) == userTag) { func(key); return; } + if ((value.user.username + (value.user.discriminator != '0' ? '#' + value.user.discriminator : ''))== userTag) { func(key); return; } }); }); } @@ -327,6 +342,9 @@ module.exports.CreateServer = function (parent) { } else if ((toData[0] == 'facebook') && (toData.length == 2)) { var url = 'https://api.callmebot.com/facebook/send.php?apikey=' + encodeURIComponent(toData[1]) + '&text=' + encodeURIComponent(msg); require('https').get(url, function (r) { if (func != null) { func(r.statusCode == 200); } }); + } else if ((toData[0] == 'telegram') && (toData.length == 2)) { + var url = 'https://api.callmebot.com/text.php?user=' + encodeURIComponent(toData[1]) + '&text=' + encodeURIComponent(msg); + require('https').get(url, function (r) { if (func != null) { func(r.statusCode == 200); } }); } } else if ((to.startsWith('pushover:')) && (obj.pushoverClient != null)) { // Pushover const Pushover = require('node-pushover'); @@ -334,8 +352,9 @@ module.exports.CreateServer = function (parent) { push.send(domain.title ? domain.title : 'MeshCentral', msg, function (err, res) { if (func != null) { func(err == null); } }); } else if ((to.startsWith('ntfy:')) && (obj.ntfyClient != null)) { // ntfy const url = 'https://' + (((typeof parent.config.messaging.ntfy == 'object') && (typeof parent.config.messaging.ntfy.host == 'string')) ? parent.config.messaging.ntfy.host : 'ntfy.sh') + '/' + encodeURIComponent(to.substring(5)); - const req = require('https').request(new URL(url), { method: 'POST' }, function (res) { if (func != null) { func(true); } }); - req.on('error', function (err) { if (func != null) { func(false); } }); + const headers = { 'User-Agent': 'MeshCentral v' + parent.currentVer }; + if (typeof parent.config.messaging.ntfy.authorization == 'string') { headers['Authorization'] = parent.config.messaging.ntfy.authorization; } + const req = require('https').request(new URL(url), { method: 'POST', headers: headers }, function (res) { if (func != null) { func(res.statusCode == 200); } }); req.end(msg); } else if ((to.startsWith('zulip:')) && (obj.zulipClient != null)) { // zulip obj.zulipClient.sendMessage({ @@ -345,9 +364,14 @@ module.exports.CreateServer = function (parent) { subject: domain.title ? domain.title : 'MeshCentral' }); if (func != null) { func(true); } + }else if ((to.startsWith('slack:')) && (obj.slackClient != null)) { //slack + const req = require('https').request(new URL(to.substring(6)), { method: 'POST' }, function (res) { if (func != null) { func(true); } }); + req.on('error', function (err) { if (func != null) { func(false); } }); + req.write(JSON.stringify({"text": msg })); + req.end(); } else { // No providers found - func(false, "No messaging providers found for this message."); + if (func != null) { func(false, "No messaging providers found for this message."); } } } @@ -355,15 +379,17 @@ module.exports.CreateServer = function (parent) { obj.callmebotUrlToHandle = function (xurl) { var url = null; try { url = require('url').parse(xurl); } catch (ex) { return; } - if ((url == null) || (url.host != 'api.callmebot.com') || (url.protocol != 'https:') || (url.query == null)) return; + if ((url == null) || (url.host != 'api.callmebot.com') || (url.query == null)) return; var urlArgs = {}, urlArgs2 = url.query.split('&'); for (var i in urlArgs2) { var j = urlArgs2[i].indexOf('='); if (j > 0) { urlArgs[urlArgs2[i].substring(0, j)] = urlArgs2[i].substring(j + 1); } } if ((urlArgs['phone'] != null) && (urlArgs['phone'].indexOf('|') >= 0)) return; if ((urlArgs['apikey'] != null) && (urlArgs['apikey'].indexOf('|') >= 0)) return; - // Signal Messenger, Whatapp and Facebook + if ((urlArgs['user'] != null) && (urlArgs['user'].indexOf('|') >= 0)) return; + // Signal Messenger, Whatapp, Facebook and Telegram if (url.path.startsWith('/signal') && (urlArgs['phone'] != null) && (urlArgs['apikey'] != null)) { return 'callmebot:signal|' + urlArgs['phone'] + '|' + urlArgs['apikey']; } if (url.path.startsWith('/whatsapp') && (urlArgs['phone'] != null) && (urlArgs['apikey'] != null)) { return 'callmebot:whatsapp|' + urlArgs['phone'] + '|' + urlArgs['apikey']; } if (url.path.startsWith('/facebook') && (urlArgs['apikey'] != null)) { return 'callmebot:facebook|' + urlArgs['apikey']; } + if (url.path.startsWith('/text') && (urlArgs['user'] != null)) { return 'callmebot:telegram|' + urlArgs['user']; } return null; } @@ -436,6 +462,224 @@ module.exports.CreateServer = function (parent) { obj.sendMessage(to, sms, domain, func); }; + // Send device state change notification + obj.sendDeviceNotify = function (domain, username, to, connections, disconnections, lang) { + if (to == null) return; + parent.debug('email', "Sending device state change message to " + to); + + // Format the message + var sms = []; + if (connections.length > 0) { sms.push('Connections: ' + connections.join(', ')); } // TODO: Translate 'Connections: ' + if (disconnections.length > 0) { sms.push('Disconnections: ' + disconnections.join(', ')); } // TODO: Translate 'Disconnections: ' + if (sms.length == 0) return; + sms = sms.join(' - '); + if (sms.length > 1000) { sms = sms.substring(0, 997) + '...'; } // Limit messages to 1000 characters + + // Send the message + obj.sendMessage(to, sms, domain, null); + }; + + // Send help request notification + obj.sendDeviceHelpRequest = function (domain, username, to, devicename, nodeid, helpusername, helprequest, lang) { + if (to == null) return; + parent.debug('email', "Sending device help request message to " + to); + + // Format the message + var sms = "Help Request from " + devicename + ': ' + helprequest; // TODO: Translate 'Help Request from {0}:' + if (sms.length > 1000) { sms = sms.substring(0, 997) + '...'; } // Limit messages to 1000 characters + + // Send the message + obj.sendMessage(to, sms, domain, null); + } + + + // + // Device connection and disconnection notifications + // + + obj.deviceNotifications = {}; // UserId --> { timer, nodes: nodeid --> connectType } + + // A device connected and a user needs to be notified about it. + obj.notifyDeviceConnect = function (user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo) { + const mesh = parent.webserver.meshes[meshid]; + if (mesh == null) return; + + // Add the user and start a timer + if (obj.deviceNotifications[user._id] == null) { + obj.deviceNotifications[user._id] = { nodes: {} }; + obj.deviceNotifications[user._id].timer = setTimeout(function () { sendDeviceNotifications(user._id); }, 1 * 60 * 1000); // 1 minute before message is sent + } + + // Add the device + if (obj.deviceNotifications[user._id].nodes[nodeid] == null) { + obj.deviceNotifications[user._id].nodes[nodeid] = { c: connectType }; // This device connection need to be added + } else { + const info = obj.deviceNotifications[user._id].nodes[nodeid]; + if ((info.d != null) && ((info.d & connectType) != 0)) { + info.d -= connectType; // This device disconnect cancels out a device connection + if (((info.c == null) || (info.c == 0)) && ((info.d == null) || (info.d == 0))) { + // This device no longer needs a notification + delete obj.deviceNotifications[user._id].nodes[nodeid]; + if (Object.keys(obj.deviceNotifications[user._id].nodes).length == 0) { + // This user no longer needs a notification + clearTimeout(obj.deviceNotifications[user._id].timer); + delete obj.deviceNotifications[user._id]; + } + return; + } + } else { + if (info.c != null) { + info.c |= connectType; // This device disconnect needs to be added + } else { + info.c = connectType; // This device disconnect needs to be added + } + } + } + + // Set the device group name + if ((extraInfo != null) && (extraInfo.name != null)) { obj.deviceNotifications[user._id].nodes[nodeid].nn = extraInfo.name; } + obj.deviceNotifications[user._id].nodes[nodeid].mn = mesh.name; + } + + // Cancel a device disconnect notification + obj.cancelNotifyDeviceDisconnect = function (user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo) { + const mesh = parent.webserver.meshes[meshid]; + if (mesh == null) return; + + if ((obj.deviceNotifications[user._id] != null) && (obj.deviceNotifications[user._id].nodes[nodeid] != null)) { + const info = obj.deviceNotifications[user._id].nodes[nodeid]; + if ((info.d != null) && ((info.d & connectType) != 0)) { + info.d -= connectType; // This device disconnect cancels out a device connection + if (((info.c == null) || (info.c == 0)) && ((info.d == null) || (info.d == 0))) { + // This device no longer needs a notification + delete obj.deviceNotifications[user._id].nodes[nodeid]; + if (Object.keys(obj.deviceNotifications[user._id].nodes).length == 0) { + // This user no longer needs a notification + clearTimeout(obj.deviceNotifications[user._id].timer); + delete obj.deviceNotifications[user._id]; + } + } + } + } + } + + // A device disconnected and a user needs to be notified about it. + obj.notifyDeviceDisconnect = function (user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo) { + const mesh = parent.webserver.meshes[meshid]; + if (mesh == null) return; + + // Add the user and start a timer + if (obj.deviceNotifications[user._id] == null) { + obj.deviceNotifications[user._id] = { nodes: {} }; + obj.deviceNotifications[user._id].timer = setTimeout(function () { sendDeviceNotifications(user._id); }, 1 * 60 * 1000); // 1 minute before message is sent + } + + // Add the device + if (obj.deviceNotifications[user._id].nodes[nodeid] == null) { + obj.deviceNotifications[user._id].nodes[nodeid] = { d: connectType }; // This device disconnect need to be added + } else { + const info = obj.deviceNotifications[user._id].nodes[nodeid]; + if ((info.c != null) && ((info.c & connectType) != 0)) { + info.c -= connectType; // This device disconnect cancels out a device connection + if (((info.d == null) || (info.d == 0)) && ((info.c == null) || (info.c == 0))) { + // This device no longer needs a notification + delete obj.deviceNotifications[user._id].nodes[nodeid]; + if (Object.keys(obj.deviceNotifications[user._id].nodes).length == 0) { + // This user no longer needs a notification + clearTimeout(obj.deviceNotifications[user._id].timer); + delete obj.deviceNotifications[user._id]; + } + return; + } + } else { + if (info.d != null) { + info.d |= connectType; // This device disconnect needs to be added + } else { + info.d = connectType; // This device disconnect needs to be added + } + } + } + + // Set the device group name + if ((extraInfo != null) && (extraInfo.name != null)) { obj.deviceNotifications[user._id].nodes[nodeid].nn = extraInfo.name; } + obj.deviceNotifications[user._id].nodes[nodeid].mn = mesh.name; + } + + // Cancel a device connect notification + obj.cancelNotifyDeviceConnect = function (user, meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo) { + const mesh = parent.webserver.meshes[meshid]; + if (mesh == null) return; + + if ((obj.deviceNotifications[user._id] != null) && (obj.deviceNotifications[user._id].nodes[nodeid] != null)) { + const info = obj.deviceNotifications[user._id].nodes[nodeid]; + if ((info.c != null) && ((info.c & connectType) != 0)) { + info.c -= connectType; // This device disconnect cancels out a device connection + if (((info.d == null) || (info.d == 0)) && ((info.c == null) || (info.c == 0))) { + // This device no longer needs a notification + delete obj.deviceNotifications[user._id].nodes[nodeid]; + if (Object.keys(obj.deviceNotifications[user._id].nodes).length == 0) { + // This user no longer needs a notification + clearTimeout(obj.deviceNotifications[user._id].timer); + delete obj.deviceNotifications[user._id]; + } + } + } + } + } + + // Send a notification about device connections and disconnections to a user + function sendDeviceNotifications(userid) { + if (obj.deviceNotifications[userid] == null) return; + clearTimeout(obj.deviceNotifications[userid].timer); + + var connections = []; + var disconnections = []; + + for (var nodeid in obj.deviceNotifications[userid].nodes) { + var info = obj.deviceNotifications[userid].nodes[nodeid]; + if ((info.c != null) && (info.c > 0) && (info.nn != null) && (info.mn != null)) { + /* + var c = []; + if (info.c & 1) { c.push("Agent"); } + if (info.c & 2) { c.push("CIRA"); } + if (info.c & 4) { c.push("AMT"); } + if (info.c & 8) { c.push("AMT-Relay"); } + if (info.c & 16) { c.push("MQTT"); } + connections.push(info.mn + ', ' + info.nn + ': ' + c.join(', ')); + */ + if (info.c & 1) { connections.push(info.nn); } + } + if ((info.d != null) && (info.d > 0) && (info.nn != null) && (info.mn != null)) { + /* + var d = []; + if (info.d & 1) { d.push("Agent"); } + if (info.d & 2) { d.push("CIRA"); } + if (info.d & 4) { d.push("AMT"); } + if (info.d & 8) { d.push("AMT-Relay"); } + if (info.d & 16) { d.push("MQTT"); } + disconnections.push(info.mn + ', ' + info.nn + ': ' + d.join(', ')); + */ + if (info.d & 1) { disconnections.push(info.nn); } + } + } + + // Sort the notifications + connections.sort(sortCollator.compare); + disconnections.sort(sortCollator.compare); + + // Get the user and domain + const user = parent.webserver.users[userid]; + if ((user == null) || (user.msghandle == null)) return; + const domain = obj.parent.config.domains[user.domain]; + if (domain == null) return; + + // Send the message + obj.sendDeviceNotify(domain, user.name, user.msghandle, connections, disconnections, user.llang); + + // Clean up + delete obj.deviceNotifications[userid]; + } + return obj; }; diff --git a/meshrelay.js b/meshrelay.js index 559bf23a..7f91904d 100644 --- a/meshrelay.js +++ b/meshrelay.js @@ -119,6 +119,9 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { try { sr = parseInt(req.query.slowrelay); } catch (ex) { } if ((typeof sr == 'number') && (sr > 0) && (sr < 1000)) { obj.ws.slowRelay = sr; } } + + // Check if protocol is set in the cookie and if so replace req.query.p but only if its not already set or blank + if ((cookie != null) && (typeof cookie.p == 'number') && (obj.req.query.p === undefined || obj.req.query.p === "")) { obj.req.query.p = cookie.p; } // Mesh Rights const MESHRIGHT_EDITMESH = 1; @@ -442,15 +445,15 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { relayinfo.peer1.sendPeerImage(); } else { // Write the recording file header - parent.parent.debug('relay', 'Relay: Started recoding to file: ' + recFullFilename); + parent.parent.debug('relay', 'Relay: Started recording to file: ' + recFullFilename); var metadata = { magic: 'MeshCentralRelaySession', ver: 1, userid: sessionUser._id, username: sessionUser.name, sessionid: obj.id, - ipaddr1: (obj.req == null) ? null : obj.req.clientIp, - ipaddr2: ((obj.peer == null) || (obj.peer.req == null)) ? null : obj.peer.req.clientIp, + ipaddr1: ((obj.peer == null) || (obj.peer.req == null)) ? null : obj.peer.req.clientIp, + ipaddr2: (obj.req == null) ? null : obj.req.clientIp, time: new Date().toLocaleString(), protocol: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.p), nodeid: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.nodeid) @@ -564,7 +567,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { } else { ws._socket.pause(); // Hold traffic until the other connection parent.parent.debug('relay', 'Relay holding: ' + obj.id + ' (' + obj.req.clientIp + ') ' + (obj.authenticated ? 'Authenticated' : '')); - parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(closeBothSides, 60000) }; + parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(closeBothSides, 15000) }; } // Check if a peer server has this connection @@ -741,32 +744,34 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { var logfile = ws.logfile; delete ws.logfile; if (peer.ws) { delete peer.ws.logfile; } - recordingEntry(logfile, 3, 0, 'MeshCentralMCREC', function (logfile, tag) { - parent.parent.fs.close(logfile.fd); + setTimeout(function(){ // wait 5 seconds before finishing file for some reason? + recordingEntry(logfile, 3, 0, 'MeshCentralMCREC', function (logfile, tag) { + parent.parent.fs.closeSync(logfile.fd); - // Now that the recording file is closed, check if we need to index this file. - if (domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', tag.logfile.filename); } + // Now that the recording file is closed, check if we need to index this file. + if (domain.sessionrecording.index && domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', tag.logfile.filename); } - // Compute session length - var sessionLength = null; - if (tag.logfile.startTime != null) { sessionLength = Math.round((Date.now() - tag.logfile.startTime) / 1000); } + // Compute session length + var sessionLength = null; + if (tag.logfile.startTime != null) { sessionLength = Math.round((Date.now() - tag.logfile.startTime) / 1000); } - // Add a event entry about this recording - var basefile = parent.parent.path.basename(tag.logfile.filename); - var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: tag.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: tag.logfile.size }; - if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; } - var xprotocol = (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.p); - if ((xprotocol == null) && (logfile.text == 2)) { xprotocol = 200; } - if (xprotocol != null) { event.protocol = parseInt(xprotocol); } - var mesh = parent.meshes[tag.logfile.meshid]; - if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; } - if (tag.logfile.startTime) { event.startTime = tag.logfile.startTime; event.lengthTime = sessionLength; } - if (tag.logfile.name) { event.name = tag.logfile.name; } - if (tag.logfile.icon) { event.icon = tag.logfile.icon; } - parent.parent.DispatchEvent(['*', 'recording', tag.logfile.nodeid, tag.logfile.meshid], obj, event); + // Add a event entry about this recording + var basefile = parent.parent.path.basename(tag.logfile.filename); + var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: tag.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: tag.logfile.size }; + if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; } + var xprotocol = (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.p); + if ((xprotocol == null) && (logfile.text == 2)) { xprotocol = 200; } + if (xprotocol != null) { event.protocol = parseInt(xprotocol); } + var mesh = parent.meshes[tag.logfile.meshid]; + if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; } + if (tag.logfile.startTime) { event.startTime = tag.logfile.startTime; event.lengthTime = sessionLength; } + if (tag.logfile.name) { event.name = tag.logfile.name; } + if (tag.logfile.icon) { event.icon = tag.logfile.icon; } + parent.parent.DispatchEvent(['*', 'recording', tag.logfile.nodeid, tag.logfile.meshid], obj, event); - cleanUpRecordings(); - }, { ws: ws, pws: peer.ws, logfile: logfile }); + cleanUpRecordings(); + }, { ws: ws, pws: peer.ws, logfile: logfile }); + },5000); } try { ws.close(); } catch (ex) { } @@ -882,7 +887,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { if (user != null) { rcookieData.ruserid = user._id; } else if (obj.nouser === true) { rcookieData.nouser = 1; } const rcookie = parent.parent.encodeCookie(rcookieData, parent.parent.loginCookieEncryptionKey); if (obj.id == null) { obj.id = parent.crypto.randomBytes(9).toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); } // If there is no connection id, generate one. - const command = { nodeid: cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/' + xdomain + 'meshrelay.ashx?id=' + obj.id + '&rauth=' + rcookie, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr, soptions: {} }; + const command = { nodeid: cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/' + xdomain + 'meshrelay.ashx?' + (obj.req.query.p != null ? ('p=' + obj.req.query.p + '&') : '') + 'id=' + obj.id + '&rauth=' + rcookie, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr, soptions: {} }; if (user) { command.userid = user._id; } if (typeof domain.consentmessages == 'object') { if (typeof domain.consentmessages.title == 'string') { command.soptions.consentTitle = domain.consentmessages.title; } @@ -891,6 +896,8 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; } if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; } if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; } + if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; } + if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; } } if (typeof domain.notificationmessages == 'object') { if (typeof domain.notificationmessages.title == 'string') { command.soptions.notifyTitle = domain.notificationmessages.title; } @@ -920,7 +927,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { if (obj.id == null) { obj.id = parent.crypto.randomBytes(9).toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); } // If there is no connection id, generate one. const rcookie = parent.parent.encodeCookie({ ruserid: user._id }, parent.parent.loginCookieEncryptionKey); if (obj.req.query.tcpport != null) { - const command = { nodeid: obj.req.query.nodeid, action: 'msg', type: 'tunnel', userid: user._id, value: '*/' + xdomain + 'meshrelay.ashx?id=' + obj.id + '&rauth=' + rcookie, tcpport: obj.req.query.tcpport, tcpaddr: ((obj.req.query.tcpaddr == null) ? '127.0.0.1' : obj.req.query.tcpaddr), soptions: {} }; + const command = { nodeid: obj.req.query.nodeid, action: 'msg', type: 'tunnel', userid: user._id, value: '*/' + xdomain + 'meshrelay.ashx?' + (obj.req.query.p != null ? ('p=' + obj.req.query.p + '&') : '') + 'id=' + obj.id + '&rauth=' + rcookie, tcpport: obj.req.query.tcpport, tcpaddr: ((obj.req.query.tcpaddr == null) ? '127.0.0.1' : obj.req.query.tcpaddr), soptions: {} }; if (typeof domain.consentmessages == 'object') { if (typeof domain.consentmessages.title == 'string') { command.soptions.consentTitle = domain.consentmessages.title; } if (typeof domain.consentmessages.desktop == 'string') { command.soptions.consentMsgDesktop = domain.consentmessages.desktop; } @@ -928,6 +935,8 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; } if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; } if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; } + if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; } + if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; } } if (typeof domain.notificationmessages == 'object') { if (typeof domain.notificationmessages.title == 'string') { command.soptions.notifyTitle = domain.notificationmessages.title; } @@ -938,14 +947,15 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { parent.parent.debug('relay', 'Relay: Sending agent TCP tunnel command: ' + JSON.stringify(command)); if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); } } else if (obj.req.query.udpport != null) { - const command = { nodeid: obj.req.query.nodeid, action: 'msg', type: 'tunnel', userid: user._id, value: '*/' + xdomain + 'meshrelay.ashx?id=' + obj.id + '&rauth=' + rcookie, udpport: obj.req.query.udpport, udpaddr: ((obj.req.query.udpaddr == null) ? '127.0.0.1' : obj.req.query.udpaddr), soptions: {} }; - if (typeof domain.consentmessages == 'object') { + const command = { nodeid: obj.req.query.nodeid, action: 'msg', type: 'tunnel', userid: user._id, value: '*/' + xdomain + 'meshrelay.ashx?' + (obj.req.query.p != null ? ('p=' + obj.req.query.p + '&') : '') + 'id=' + obj.id + '&rauth=' + rcookie, udpport: obj.req.query.udpport, udpaddr: ((obj.req.query.udpaddr == null) ? '127.0.0.1' : obj.req.query.udpaddr), soptions: {} }; if (typeof domain.consentmessages == 'object') { if (typeof domain.consentmessages.title == 'string') { command.soptions.consentTitle = domain.consentmessages.title; } if (typeof domain.consentmessages.desktop == 'string') { command.soptions.consentMsgDesktop = domain.consentmessages.desktop; } if (typeof domain.consentmessages.terminal == 'string') { command.soptions.consentMsgTerminal = domain.consentmessages.terminal; } if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; } if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; } if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; } + if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; } + if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; } } if (typeof domain.notificationmessages == 'object') { if (typeof domain.notificationmessages.title == 'string') { command.soptions.notifyTitle = domain.notificationmessages.title; } @@ -997,6 +1007,8 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) { if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; } if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; } if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; } + if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; } + if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; } } if (typeof domain.notificationmessages == 'object') { if (typeof domain.notificationmessages.title == 'string') { command.soptions.notifyTitle = domain.notificationmessages.title; } @@ -1225,6 +1237,7 @@ function CreateLocalRelayEx(parent, ws, req, domain, user, cookie) { else if (req.query.p == 11) { protocolStr = 'SSH-TERM'; } else if (req.query.p == 12) { protocolStr = 'VNC'; } else if (req.query.p == 13) { protocolStr = 'SSH-FILES'; } + else if (req.query.p == 14) { protocolStr = 'Web-TCP'; } var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: obj.user._id, username: obj.user.name, msgid: 121, msgArgs: [obj.id, protocolStr, obj.host, Math.floor((Date.now() - obj.time) / 1000)], msg: 'Ended local relay session \"' + obj.id + '\", protocol ' + protocolStr + ' to ' + obj.host + ', ' + Math.floor((Date.now() - obj.time) / 1000) + ' second(s)', nodeid: obj.req.query.nodeid, protocol: req.query.p, in: inTraffc, out: outTraffc }; if (obj.guestname) { event.guestname = obj.guestname; } // If this is a sharing session, set the guest name here. parent.parent.DispatchEvent(['*', user._id], obj, event); @@ -1279,6 +1292,7 @@ function CreateLocalRelayEx(parent, ws, req, domain, user, cookie) { else if (req.query.p == 11) { protocolStr = 'SSH-TERM'; } else if (req.query.p == 12) { protocolStr = 'VNC'; } else if (req.query.p == 13) { protocolStr = 'SSH-FILES'; } + else if (req.query.p == 14) { protocolStr = 'Web-TCP'; } obj.time = Date.now(); var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: obj.user._id, username: obj.user.name, msgid: 120, msgArgs: [obj.id, protocolStr, obj.host], msg: 'Started local relay session \"' + obj.id + '\", protocol ' + protocolStr + ' to ' + obj.host, nodeid: req.query.nodeid, protocol: req.query.p }; if (obj.guestname) { event.guestname = obj.guestname; } // If this is a sharing session, set the guest name here. @@ -1317,4 +1331,4 @@ function CreateLocalRelayEx(parent, ws, req, domain, user, cookie) { // If this is not an authenticated session, or the session does not have routing instructions, just go ahead an connect to existing session. performRelay(); return obj; -}; \ No newline at end of file +}; diff --git a/meshuser.js b/meshuser.js index 40f035af..ac237dfd 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1,4 +1,4 @@ -/** +/** * @description MeshCentral MeshAgent * @author Ylian Saint-Hilaire & Bryan Roe * @copyright Intel Corporation 2018-2022 @@ -84,7 +84,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use const PROTOCOL_WEBVNC = 204; // MeshCentral Satellite - const SATELLITE_PRESENT = 1; // This session is a MeshCentral Salellite session + const SATELLITE_PRESENT = 1; // This session is a MeshCentral Satellite session const SATELLITE_802_1x = 2; // This session supports 802.1x profile checking and creation // Events @@ -600,7 +600,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } } if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; } - if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) { serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); } + if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) {serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); } + if (typeof domain.logoutonidlesessiontimeout == 'boolean') { + serverinfo.logoutonidlesessiontimeout = domain.logoutonidlesessiontimeout; + } else { + // Default + serverinfo.logoutonidlesessiontimeout = true; + } if (user.siteadmin === SITERIGHT_ADMIN) { if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { serverinfo.manageAllDeviceGroups = true; } if (obj.crossDomain === true) { serverinfo.crossDomain = []; for (var i in parent.parent.config.domains) { serverinfo.crossDomain.push(i); } } @@ -778,10 +784,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Remove SSH credentials if present if (docs[i].ssh != null) { - if ((docs[i].ssh[obj.user._id] != null) && (docs[i].ssh[obj.user._id].u)) { - if (docs[i].ssh.k && docs[i].ssh[obj.user._id].kp) { docs[i].ssh = 2; } // Username, key and password - else if (docs[i].ssh[obj.user._id].k) { docs[i].ssh = 3; } // Username and key. No password. - else if (docs[i].ssh[obj.user._id].p) { docs[i].ssh = 1; } // Username and password + if ((docs[i].ssh[user._id] != null) && (docs[i].ssh[user._id].u)) { + if (docs[i].ssh.k && docs[i].ssh[user._id].kp) { docs[i].ssh = 2; } // Username, key and password + else if (docs[i].ssh[user._id].k) { docs[i].ssh = 3; } // Username and key. No password. + else if (docs[i].ssh[user._id].p) { docs[i].ssh = 1; } // Username and password else { delete docs[i].ssh; } } else { delete docs[i].ssh; @@ -789,7 +795,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } // Remove RDP credentials if present, only set to 1 if our userid has RDP credentials - if ((docs[i].rdp != null) && (docs[i].rdp[obj.user._id] != null)) { docs[i].rdp = 1; } else { delete docs[i].rdp; } + if ((docs[i].rdp != null) && (docs[i].rdp[user._id] != null)) { docs[i].rdp = 1; } else { delete docs[i].rdp; } // Remove Intel AMT credential if present if (docs[i].intelamt != null) { @@ -815,6 +821,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((xipkvmport != null) && (xipkvmport.sessions != null)) { docs[i].sessions = xipkvmport.sessions; } } + // Patch node links with names, like meshes links with names + for (var a in docs[i].links) { + if (!docs[i].links[a].name) { + if (parent.users[a] && parent.users[a].realname) { docs[i].links[a].name = parent.users[a].realname; } + else if (parent.users[a] && parent.users[a].name) { docs[i].links[a].name = parent.users[a].name; } + } + } + r[meshid].push(docs[i]); } const response = { action: 'nodes', responseid: command.responseid, nodes: r, tag: command.tag }; @@ -898,14 +912,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } else if ((command.fileop == 'copy') || (command.fileop == 'move')) { // Copy or move of one or many files - if (common.validateArray(command.name, 1) == false) return; - var scpath = meshPathToRealPath(command.path, user); // This will also check access rights + if (common.validateArray(command.names, 1) == false) return; + var scpath = meshPathToRealPath(command.scpath, user); // This will also check access rights if (scpath == null) break; // TODO: Check quota if this is a copy for (i in command.names) { if (common.IsFilenameValid(command.names[i]) === true) { var s = parent.path.join(scpath, command.names[i]), d = parent.path.join(path, command.names[i]); sendUpdate = false; + try { fs.mkdirSync(path); } catch (ex) { } // try to create folder first incase folder is missing copyFile(s, d, function (op) { if (op != null) { fs.unlink(op, function (err) { parent.parent.DispatchEvent([user._id], obj, 'updatefiles'); }); } else { parent.parent.DispatchEvent([user._id], obj, 'updatefiles'); } }, ((command.fileop == 'move') ? s : null)); } } @@ -913,7 +928,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Get a short file and send it back on the web socket if (common.validateString(command.file, 1, 4096) == false) return; const scpath = meshPathToRealPath(command.path, user); // This will also check access rights - if (scpath == null) break; + if ((scpath == null) || (command.file !== parent.path.basename(command.file))) break; const filePath = parent.path.join(scpath, command.file); fs.stat(filePath, function (err, stat) { if ((err != null) || (stat == null) || (stat.size >= 204800)) return; @@ -928,7 +943,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (common.validateString(command.file, 1, 4096) == false) return; if (typeof command.data != 'string') return; const scpath = meshPathToRealPath(command.path, user); // This will also check access rights - if (scpath == null) break; + if ((scpath == null) || (command.file !== parent.path.basename(command.file))) break; const filePath = parent.path.join(scpath, command.file); var data = null; try { data = Buffer.from(command.data, 'base64'); } catch (ex) { return; } @@ -988,6 +1003,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; } if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; } if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; } + if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; } + if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; } } if (typeof domain.notificationmessages == 'object') { if (typeof domain.notificationmessages.title == 'string') { command.soptions.notifyTitle = domain.notificationmessages.title; } @@ -1021,15 +1038,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // TODO: Add the meshes command.userid has access to (???) var filter = [command.userid]; + var actionfilter = null; + if (command.filter != null) { + if (['agentlog','batchupload','changenode','manual','relaylog','removenode','runcommands'].includes(command.filter)) actionfilter = command.filter; + } + if ((command.limit == null) || (typeof command.limit != 'number')) { // Send the list of all events for this session - db.GetUserEvents(filter, domain.id, command.userid, function (err, docs) { + db.GetUserEvents(filter, domain.id, command.userid, actionfilter, function (err, docs) { if (err != null) return; try { ws.send(JSON.stringify({ action: 'events', events: docs, userid: command.userid, tag: command.tag })); } catch (ex) { } }); } else { // Send the list of most recent events for this session, up to 'limit' count - db.GetUserEventsWithLimit(filter, domain.id, command.userid, command.limit, function (err, docs) { + db.GetUserEventsWithLimit(filter, domain.id, command.userid, command.limit, actionfilter, function (err, docs) { if (err != null) return; try { ws.send(JSON.stringify({ action: 'events', events: docs, userid: command.userid, tag: command.tag })); } catch (ex) { } }); @@ -1047,15 +1069,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var limit = 10000; if (common.validateInt(command.limit, 1, 1000000) == true) { limit = command.limit; } + var filter = null; + if (command.filter != null) { + if (['agentlog','batchupload','changenode','manual','relaylog','removenode','runcommands'].includes(command.filter)) filter = command.filter; + } + if (((rights & MESHRIGHT_LIMITEVENTS) != 0) && (rights != MESHRIGHT_ADMIN)) { // Send the list of most recent events for this nodeid that only apply to us, up to 'limit' count - db.GetNodeEventsSelfWithLimit(node._id, domain.id, user._id, limit, function (err, docs) { + db.GetNodeEventsSelfWithLimit(node._id, domain.id, user._id, limit, filter, function (err, docs) { if (err != null) return; try { ws.send(JSON.stringify({ action: 'events', events: docs, nodeid: node._id, tag: command.tag })); } catch (ex) { } }); } else { // Send the list of most recent events for this nodeid, up to 'limit' count - db.GetNodeEventsWithLimit(node._id, domain.id, limit, function (err, docs) { + db.GetNodeEventsWithLimit(node._id, domain.id, limit, filter, function (err, docs) { if (err != null) return; try { ws.send(JSON.stringify({ action: 'events', events: docs, nodeid: node._id, tag: command.tag })); } catch (ex) { } }); @@ -1075,15 +1102,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use for (var link in obj.user.links) { if (((obj.user.links[link].rights & MESHRIGHT_LIMITEVENTS) != 0) && ((obj.user.links[link].rights != MESHRIGHT_ADMIN))) { exGroupFilter2.push(link); } } for (var i in filter2) { if (exGroupFilter2.indexOf(filter2[i]) == -1) { filter.push(filter2[i]); } } + var actionfilter = null; + if (command.filter != null) { + if (['agentlog','batchupload','changenode','manual','relaylog','removenode','runcommands'].includes(command.filter)) actionfilter = command.filter; + } + if ((command.limit == null) || (typeof command.limit != 'number')) { // Send the list of all events for this session - db.GetEvents(filter, domain.id, function (err, docs) { + db.GetEvents(filter, domain.id, actionfilter, function (err, docs) { if (err != null) return; try { ws.send(JSON.stringify({ action: 'events', events: docs, user: command.user, tag: command.tag })); } catch (ex) { } }); } else { // Send the list of most recent events for this session, up to 'limit' count - db.GetEventsWithLimit(filter, domain.id, command.limit, function (err, docs) { + db.GetEventsWithLimit(filter, domain.id, command.limit, actionfilter, function (err, docs) { if (err != null) return; try { ws.send(JSON.stringify({ action: 'events', events: docs, user: command.user, tag: command.tag })); } catch (ex) { } }); @@ -1100,7 +1132,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (err != null) { try { ws.send(JSON.stringify({ action: 'recordings', error: 1, tag: command.tag })); } catch (ex) { } return; } if ((command.limit == null) || (typeof command.limit != 'number')) { // Send the list of all recordings - db.GetEvents(['recording'], domain.id, function (err, docs) { + db.GetEvents(['recording'], domain.id, null, function (err, docs) { if (err != null) { try { ws.send(JSON.stringify({ action: 'recordings', error: 2, tag: command.tag })); } catch (ex) { } return; } for (var i in docs) { delete docs[i].action; delete docs[i].etype; delete docs[i].msg; // TODO: We could make a more specific query in the DB and never have these. @@ -1110,7 +1142,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use }); } else { // Send the list of most recent recordings, up to 'limit' count - db.GetEventsWithLimit(['recording'], domain.id, command.limit, function (err, docs) { + db.GetEventsWithLimit(['recording'], domain.id, command.limit, null, function (err, docs) { if (err != null) { try { ws.send(JSON.stringify({ action: 'recordings', error: 2, tag: command.tag })); } catch (ex) { } return; } for (var i in docs) { delete docs[i].action; delete docs[i].etype; delete docs[i].msg; // TODO: We could make a more specific query in the DB and never have these. @@ -1395,7 +1427,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; } if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete chguser.phone; } else { chguser.phone = command.phone; } change = 1; } if ((command.msghandle != null) && (typeof command.msghandle == 'string')) { - if (command.msghandle.startsWith('callmebot:https://')) { const h = parent.parent.msgserver.callmebotUrlToHandle(command.msghandle.substring(10)); if (h) { command.msghandle = h; } else { command.msghandle = ''; } } + if (command.msghandle.startsWith('callmebot:http')) { const h = parent.parent.msgserver.callmebotUrlToHandle(command.msghandle.substring(10)); if (h) { command.msghandle = h; } else { command.msghandle = ''; } } if (command.msghandle == '') { delete chguser.msghandle; } else { chguser.msghandle = command.msghandle; } change = 1; } @@ -1490,6 +1522,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use { var ugrpdomain, err = null; try { + // Check if we are in a mode that does not allow manual user group creation + if ( + (typeof domain.authstrategies == 'object') && + (typeof domain.authstrategies['oidc'] == 'object') && + (typeof domain.authstrategies['oidc'].groups == 'object') && + ((domain.authstrategies['oidc'].groups.sync == true) || ((typeof domain.authstrategies['oidc'].groups.sync == 'object') && (domain.authstrategies['oidc'].groups.sync.enabled == true))) + ) { + err = "Not allowed in OIDC mode with user group sync."; + } + // Check if we have new group restriction if ((user.siteadmin & SITERIGHT_USERGROUPS) == 0) { err = "Permission denied"; } @@ -1717,12 +1759,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use { if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here. - // 2 = WebPage device connections - // 4 = WebPage device disconnections - // 8 = WebPage device desktop and serial events - // 16 = Email device connections - // 32 = Email device disconnections - // 64 = Email device help request + // 2 = WebPage device connections + // 4 = WebPage device disconnections + // 8 = WebPage device desktop and serial events + // 16 = Email device connections + // 32 = Email device disconnections + // 64 = Email device help request + // 128 = Messaging device connections + // 256 = Messaging device disconnections + // 512 = Messaging device help request var err = null; try { @@ -1767,12 +1812,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use { if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here. - // 2 = WebPage device connections - // 4 = WebPage device disconnections - // 8 = WebPage device desktop and serial events - // 16 = Email device connections - // 32 = Email device disconnections - // 64 = Email device help request + // 2 = WebPage device connections + // 4 = WebPage device disconnections + // 8 = WebPage device desktop and serial events + // 16 = Email device connections + // 32 = Email device disconnections + // 64 = Email device help request + // 128 = Messaging device connections + // 256 = Messaging device disconnections + // 512 = Messaging device help request var err = null; try { @@ -1814,7 +1862,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // If this account is settings locked, return here. if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; - + + // Do not allow change password if sspi or ldap + if ((domain.auth == 'sspi') || (domain.auth == 'ldap')) return; + // Change our own password if (common.validateString(command.oldpass, 1, 256) == false) break; if (common.validateString(command.newpass, 1, 256) == false) break; @@ -2374,7 +2425,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } try { - if (common.validateString(command.userid, 8, 1024) == false) { err = "Invalid userid"; } // Check userid + if (common.validateString(command.userid, 1, 1024) == false) { err = "Invalid userid"; } // Check userid if (common.validateString(command.meshid, 8, 134) == false) { err = "Invalid groupid"; } // Check meshid if (command.userid.indexOf('/') == -1) { command.userid = 'user/' + domain.id + '/' + command.userid; } if (command.userid == obj.user._id) { err = "Can't remove self"; } // Can't add of modify self @@ -2511,77 +2562,98 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'addlocaldevice': { - if (common.validateString(command.meshid, 8, 134) == false) break; // Check meshid - if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain - if (common.validateString(command.devicename, 1, 256) == false) break; // Check device name - if (common.validateString(command.hostname, 1, 256) == false) break; // Check hostname - if (typeof command.type != 'number') break; // Type must be a number - if ((command.type != 4) && (command.type != 6) && (command.type != 29)) break; // Check device type - - // Get the mesh - mesh = parent.meshes[command.meshid]; - if (mesh) { - if (mesh.mtype != 3) return; // This operation is only allowed for mesh type 3, local device agentless mesh. - - // Check if this user has rights to do this - if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return; - - // Create a new nodeid - parent.crypto.randomBytes(48, function (err, buf) { - // Create the new node - nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); - var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 3, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, agent: { id: command.type, caps: 0 } }; - db.Set(device); - - // Event the new node - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id }); - }); + var err = null; + // Perform input validation + try { + if (common.validateString(command.meshid, 8, 134) == false) { err = "Invalid device group id"; } // Check meshid + if (common.validateString(command.devicename, 1, 256) == false) { err = "Invalid devicename"; } // Check device name + if (common.validateString(command.hostname, 1, 256) == false) { err = "Invalid hostname"; } // Check hostname + if (typeof command.type != 'number') { err = "Invalid type"; } // Type must be a number + if ((command.type != 4) && (command.type != 6) && (command.type != 29)) { err = "Invalid type"; } // Check device type + else { + if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; } + mesh = parent.meshes[command.meshid]; + if (mesh == null) { err = "Unknown device group"; } + if (mesh.mtype != 3) { err = "Local device agentless mesh only allowed" } // This operation is only allowed for mesh type 3, local device agentless mesh. + else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) { err = "Permission denied"; } + else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = "Invalid domain"; } // Invalid domain, operation only valid for current domain + } + } catch (ex) { console.log(ex); err = "Validation exception: " + ex; } + // Handle any errors + if (err != null) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: err })); } catch (ex) { } } + break; } + // Create a new nodeid + parent.crypto.randomBytes(48, function (err, buf) { + // Create the new node + nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); + var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 3, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, agent: { id: command.type, caps: 0 } }; + db.Set(device); + + // Event the new node + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id }); + // Send response if required + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'addlocaldevice', responseid: command.responseid, result: 'ok' })); } catch (ex) { } } + }); break; } case 'addamtdevice': { if (args.wanonly == true) return; // This is a WAN-only server, local Intel AMT computers can't be added - if (common.validateString(command.meshid, 8, 134) == false) break; // Check meshid - if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain - if (common.validateString(command.devicename, 1, 256) == false) break; // Check device name - if (common.validateString(command.hostname, 1, 256) == false) break; // Check hostname - if (common.validateString(command.amtusername, 0, 16) == false) break; // Check username - if (common.validateString(command.amtpassword, 0, 16) == false) break; // Check password - if (command.amttls == '0') { command.amttls = 0; } else if (command.amttls == '1') { command.amttls = 1; } // Check TLS flag - if ((command.amttls != 1) && (command.amttls != 0)) break; + var err = null; + // Perform input validation + try { + if (common.validateString(command.meshid, 8, 134) == false) { err = "Invalid device group id"; } // Check meshid + if (common.validateString(command.devicename, 1, 256) == false) { err = "Invalid devicename"; } // Check device name + if (common.validateString(command.hostname, 1, 256) == false) { err = "Invalid hostname"; } // Check hostname + if (common.validateString(command.amtusername, 0, 16) == false) { err = "Invalid amtusername"; } // Check username + if (common.validateString(command.amtpassword, 0, 16) == false) { err = "Invalid amtpassword"; } // Check password + if (command.amttls == '0') { command.amttls = 0; } else if (command.amttls == '1') { command.amttls = 1; } // Check TLS flag + if ((command.amttls != 1) && (command.amttls != 0)) { err = "Invalid amttls"; } + else { + if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; } + // Get the mesh + mesh = parent.meshes[command.meshid]; + if (mesh == null) { err = "Unknown device group"; } + if (mesh.mtype != 1) { err = "Intel AMT agentless mesh only allowed"; } // This operation is only allowed for mesh type 1, Intel AMT agentless mesh. + // Check if this user has rights to do this + else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) { err = "Permission denied"; } + else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = "Invalid domain"; } // Invalid domain, operation only valid for current domain + } + } catch (ex) { console.log(ex); err = "Validation exception: " + ex; } + + // Handle any errors + if (err != null) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeDeviceMesh', responseid: command.responseid, result: err })); } catch (ex) { } } + break; + } // If we are in WAN-only mode, hostname is not used if ((args.wanonly == true) && (command.hostname)) { delete command.hostname; } - // Get the mesh - mesh = parent.meshes[command.meshid]; - if (mesh) { - if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh. + // Create a new nodeid + parent.crypto.randomBytes(48, function (err, buf) { + // Create the new node + nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); + var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 1, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: command.amttls } }; - // Check if this user has rights to do this - if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return; + // Add optional feilds + if (common.validateInt(command.state, 0, 3)) { device.intelamt.state = command.state; } + if (common.validateString(command.ver, 1, 16)) { device.intelamt.ver = command.ver; } + if (common.validateString(command.hash, 1, 256)) { device.intelamt.hash = command.hash; } + if (common.validateString(command.realm, 1, 256)) { device.intelamt.realm = command.realm; } - // Create a new nodeid - parent.crypto.randomBytes(48, function (err, buf) { - // Create the new node - nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); - var device = { type: 'node', _id: nodeid, meshid: command.meshid, mtype: 1, icon: 1, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: command.amttls } }; + // Save the device to the database + db.Set(device); - // Add optional feilds - if (common.validateInt(command.state, 0, 3)) { device.intelamt.state = command.state; } - if (common.validateString(command.ver, 1, 16)) { device.intelamt.ver = command.ver; } - if (common.validateString(command.hash, 1, 256)) { device.intelamt.hash = command.hash; } - if (common.validateString(command.realm, 1, 256)) { device.intelamt.realm = command.realm; } + // Event the new node + parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id }); + // Send response if required + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'addamtdevice', responseid: command.responseid, result: 'ok' })); } catch (ex) { } } + }); - // Save the device to the database - db.Set(device); - - // Event the new node - parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(command.meshid, [nodeid]), obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: parent.CloneSafeNode(device), msgid: 84, msgArgs: [command.devicename, mesh.name], msg: 'Added device ' + command.devicename + ' to device group ' + mesh.name, domain: domain.id }); - }); - } break; } case 'scanamtdevice': @@ -2719,8 +2791,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use { if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's for (i in command.nodeids) { + var nodeid = command.nodeids[i], err = null; + + // Argument validation + if (common.validateString(nodeid, 1, 1024) == false) { err = 'Invalid nodeid'; } // Check nodeid + else { + if (nodeid.indexOf('/') == -1) { nodeid = 'node/' + domain.id + '/' + nodeid; } + if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain + } + if (err != null) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'removedevices', responseid: command.responseid, result: err })); } catch (ex) { } } + continue; + } // Get the node and the rights for this node - parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) { + parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) { // Check we have the rights to delete this device if ((rights & MESHRIGHT_UNINSTALL) == 0) return; @@ -2775,6 +2859,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } }); } + + // Send response if required, in this case we always send ok which is not ideal. + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'removedevices', responseid: command.responseid, result: 'ok' })); } catch (ex) { } } + break; } case 'wakedevices': @@ -2867,6 +2955,48 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } break; } + case 'webrelay': + { + if (common.validateString(command.nodeid, 8, 128) == false) { err = 'Invalid node id'; } // Check the nodeid + else if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; } + else if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain + else if ((command.port != null) && (common.validateInt(command.port, 1, 65535) == false)) { err = 'Invalid port value'; } // Check the port if present + else { + if (command.nodeid.split('/').length == 1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; } + var snode = command.nodeid.split('/'); + if ((snode.length != 3) || (snode[0] != 'node') || (snode[1] != domain.id)) { err = 'Invalid node id'; } + } + // Handle any errors + if (err != null) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'webrelay', responseid: command.responseid, result: err })); } catch (ex) { } } + break; + } + // Get the device rights + parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { + // If node not found or we don't have remote control, reject. + if (node == null) { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'webrelay', responseid: command.responseid, result: 'Invalid node id' })); } catch (ex) { } } + return; + } + var relayid = null; + var addr = null; + if (node.mtype == 3) { // Setup device relay if needed + var mesh = parent.meshes[node.meshid]; + if (mesh && mesh.relayid) { relayid = mesh.relayid; addr = node.host; } + } + var webRelayDns = (args.relaydns != null) ? args.relaydns[0] : obj.getWebServerName(domain, req); + var webRelayPort = ((args.relaydns != null) ? ((typeof args.aliasport == 'number') ? args.aliasport : args.port) : ((parent.webrelayserver != null) ? ((typeof args.relayaliasport == 'number') ? args.relayaliasport : parent.webrelayserver.port) : 0)); + if (webRelayPort == 0) { try { ws.send(JSON.stringify({ action: 'webrelay', responseid: command.responseid, result: 'WebRelay Disabled' })); return; } catch (ex) { } } + const authRelayCookie = parent.parent.encodeCookie({ ruserid: user._id, x: req.session.x }, parent.parent.loginCookieEncryptionKey); + var url = 'https://' + webRelayDns + ':' + webRelayPort + '/control-redirect.ashx?n=' + command.nodeid + '&p=' + command.port + '&appid=' + command.appid + '&c=' + authRelayCookie; + if (addr != null) { url += '&addr=' + addr; } + if (relayid != null) { url += '&relayid=' + relayid } + command.url = url; + if (command.responseid != null) { command.result = 'OK'; } + try { ws.send(JSON.stringify(command)); } catch (ex) { } + }); + break; + } case 'runcommands': { if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's @@ -2907,13 +3037,19 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use return; } - // Send the commands to the agent - var agent = parent.wsagents[node._id]; - if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) { - try { agent.send(JSON.stringify({ action: 'msg', type: 'console', value: command.cmds, rights: rights, sessionid: ws.sessionId })); } catch (ex) { } + var theCommand = { action: 'msg', type: 'console', value: command.cmds, rights: rights, sessionid: ws.sessionId }; + if (parent.parent.multiServer != null) { // peering setup + parent.parent.multiServer.DispatchMessage({ action: 'agentCommand', nodeid: node._id, command: theCommand}); if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } } } else { - if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } } + // Send the commands to the agent + var agent = parent.wsagents[node._id]; + if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) { + try { agent.send(JSON.stringify(theCommand)); } catch (ex) { } + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } } + } else { + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } } + } } } else { // This is a standard (bash/shell/powershell) command. @@ -2924,38 +3060,47 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use return; } - // Get the agent and run the commands - var agent = parent.wsagents[node._id]; - if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) { - // Check if this agent is correct for this command type - // command.type 1 = Windows Command, 2 = Windows PowerShell, 3 = Linux/BSD/macOS - var commandsOk = false; - if ((agent.agentInfo.agentId > 0) && (agent.agentInfo.agentId < 5)) { - // Windows Agent - if ((command.type == 1) || (command.type == 2)) { commandsOk = true; } - else if (command.type === 0) { command.type = 1; commandsOk = true; } // Set the default type of this agent - } else { - // Non-Windows Agent - if (command.type == 3) { commandsOk = true; } - else if (command.type === 0) { command.type = 3; commandsOk = true; } // Set the default type of this agent - } - if (commandsOk == true) { + if (typeof command.reply != 'boolean') command.reply = false; + if (typeof command.responseid != 'string') command.responseid = null; + var msgid = 24; // "Running commands" + if (command.type == 1) { msgid = 99; } // "Running commands as user" + if (command.type == 2) { msgid = 100; } // "Running commands as user if possible" + // Check if this agent is correct for this command type + // command.type 1 = Windows Command, 2 = Windows PowerShell, 3 = Linux/BSD/macOS + var commandsOk = false; + if ((node.agent.id > 0) && (node.agent.id < 5)) { + // Windows Agent + if ((command.type == 1) || (command.type == 2)) { commandsOk = true; } + else if (command.type === 0) { command.type = 1; commandsOk = true; } // Set the default type of this agent + } else { + // Non-Windows Agent + if (command.type == 3) { commandsOk = true; } + else if (command.type === 0) { command.type = 3; commandsOk = true; } // Set the default type of this agent + } + if (commandsOk == true) { + var theCommand = { action: 'runcommands', type: command.type, cmds: command.cmds, runAsUser: command.runAsUser, reply: command.reply, responseid: command.responseid }; + var agent = parent.wsagents[node._id]; + if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) { // Send the commands to the agent - try { agent.send(JSON.stringify({ action: 'runcommands', type: command.type, cmds: command.cmds, runAsUser: command.runAsUser })); } catch (ex) { } - if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } } - + try { agent.send(JSON.stringify(theCommand)); } catch (ex) { } + if (command.responseid != null && command.reply == false) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } } // Send out an event that these commands where run on this device var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]); - var msgid = 24; // "Running commands" - if (command.type == 1) { msgid = 99; } // "Running commands as user" - if (command.type == 2) { msgid = 100; } // "Running commands as user if possible" var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id }; parent.parent.DispatchEvent(targets, obj, event); + } else if (parent.parent.multiServer != null) { // peering setup + // Send the commands to the agent + parent.parent.multiServer.DispatchMessage({ action: 'agentCommand', nodeid: node._id, command: theCommand}); + if (command.responseid != null && command.reply == false) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } } + // Send out an event that these commands where run on this device + var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]); + var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id }; + parent.parent.multiServer.DispatchEvent(targets, obj, event); } else { - if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid command type' })); } catch (ex) { } } + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } } } } else { - if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } } + if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid command type' })); } catch (ex) { } } } } }); @@ -3068,8 +3213,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } if ((command.actiontype >= 300) && (command.actiontype < 400)) { - if ((command.actiontype != 302) && (command.actiontype != 308) && (command.actiontype < 310) && (command.actiontype > 312)) return; // Invalid action type. - // Intel AMT power command, actiontype: 2 = Power on, 8 = Power down, 10 = reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL + if ((command.actiontype != 302) && (command.actiontype != 308) && (command.actiontype < 310) && (command.actiontype > 316)) return; // Invalid action type. + // Intel AMT power command, actiontype: 2 = Power on, 8 = Power down, 10 = reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE parent.parent.DispatchEvent('*', obj, { action: 'amtpoweraction', userid: user._id, username: user.name, nodeids: [node._id], domain: domain.id, nolog: 1, actiontype: command.actiontype - 300 }); } else { if ((command.actiontype < 2) && (command.actiontype > 4)) return; // Invalid action type. @@ -3165,6 +3310,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changedevice', responseid: command.responseid, result: 'Access Denied' })); } catch (ex) { } } return; } + node = common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials var mesh = parent.meshes[node.meshid], amtchange = 0; // Ready the node change event @@ -3486,6 +3632,41 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use parent.parent.DispatchEvent(targets, obj, event); break; } + case 'otpduo': + { + // Do not allow this command if 2FA's are locked + if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return; + + // Do not allow if Duo is not supported + if ((typeof domain.duo2factor != 'object') || (typeof domain.duo2factor.integrationkey != 'string') || (typeof domain.duo2factor.secretkey != 'string') || (typeof domain.duo2factor.apihostname != 'string')) return; + + // Do not allow if Duo is disabled + if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.duo2factor == false)) return; + + // Do not allow this command when logged in using a login token + if (req.session.loginToken != null) break; + + if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here. + + // Check input + if ((typeof command.enabled != 'boolean') || (command.enabled != false)) return; + + // See if we really need to change the state + if ((command.enabled === false) && (user.otpduo == null)) return; + + // Change the duo 2FA of this user + delete user.otpduo; + parent.db.SetUser(user); + ws.send(JSON.stringify({ action: 'otpduo', success: true, enabled: command.enabled })); // Report success + + // Notify change + var targets = ['*', 'server-users', user._id]; + if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } } + var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msgid: command.enabled ? 160 : 161, msg: command.enabled ? "Enabled duo two-factor authentication." : "Disabled duo two-factor authentication.", domain: domain.id }; + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come. + parent.parent.DispatchEvent(targets, obj, event); + break; + } case 'otpauth-request': { // Do not allow this command if 2FA's are locked @@ -3509,7 +3690,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use const secret = otplib.authenticator.generateSecret(); // TODO: Check the random source of this value. var domainName = parent.certificates.CommonName; - if (domain.dns != null) { domainName = domain.dns; } + if (domain.dns != null) { + domainName = domain.dns; + } else if (domain.dns == null && domain.id != '') { + domainName += "/" + domain.id; + } ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.authenticator.keyuri(encodeURIComponent(user.name), domainName, secret) })); } break; @@ -4264,7 +4449,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } // If we have view only remote desktop rights, force view-only on the guest share. - if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_REMOTEVIEWONLY) != 0)) { command.viewOnly = true; command.p = (command.p & 1); } + if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_REMOTEVIEWONLY) != 0)) { command.viewOnly = true; } // Create cookie var publicid = getRandomPassword(), startTime = null, expireTime = null, duration = null; @@ -4537,7 +4722,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } else { try { parent.parent.pluginHandler.plugins[command.plugin].serveraction(command, obj, parent); - } catch (ex) { console.log('Error loading plugin handler (' + e + ')'); } + } catch (ex) { console.log('Error loading plugin handler (' + ex + ')'); } } break; } @@ -4567,6 +4752,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (typeof command.logmsg == 'string') { message.msg = command.logmsg; } else { message.nolog = 1; } parent.parent.DispatchEvent(['*', user._id], obj, message); } + + if (parent.parent.pluginHandler != null) // If the plugin's are not supported, reject this command. + { + command.userid = user._id; + try { + for( var pluginName in parent.parent.pluginHandler.plugins) + if( typeof parent.parent.pluginHandler.plugins[pluginName].uiCustomEvent === 'function' ) + parent.parent.pluginHandler.plugins[pluginName].uiCustomEvent(command, obj); + } catch (ex) { console.log('Error loading plugin handler (' + ex + ')'); } + } break; } case 'serverBackup': { @@ -4737,7 +4932,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use }); } else { // Old way - db.GetUserEvents([user._id], domain.id, user._id, function (err, docs) { + db.GetUserEvents([user._id], domain.id, user._id, null, function (err, docs) { if (err != null) return; var e = []; for (var i in docs) { @@ -4763,7 +4958,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use }); } else { // Old way - db.GetUserEvents([command.userid], domain.id, user._id, function (err, docs) { + db.GetUserEvents([command.userid], domain.id, user._id, null, function (err, docs) { if (err != null) return; var e = []; for (var i in docs) { if ((docs[i].msgArgs) && (docs[i].userid == command.userid) && ((docs[i].action == 'authfail') || (docs[i].action == 'login'))) { e.push({ t: docs[i].time, m: docs[i].msgid, a: docs[i].msgArgs }); } } @@ -4881,195 +5076,295 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use case 'getDeviceDetails': { if ((common.validateStrArray(command.nodeids, 1) == false) && (command.nodeids != null)) break; // Check nodeids if (common.validateString(command.type, 3, 4) == false) break; // Check type + + const links = parent.GetAllMeshIdWithRights(user); + const extraids = getUserExtraIds(); + db.GetAllTypeNoTypeFieldMeshFiltered(links, extraids, domain.id, 'node', null, obj.deviceSkip, obj.deviceLimit, function (err, docs) { + if (docs == null) return; + const ids = []; + if (command.nodeids != null) { + // Create a list of node ids and query them for last device connection time + for (var i in command.nodeids) { ids.push('lc' + command.nodeids[i]); } + } else { + // Create a list of node ids for this user and query them for last device connection time + for (var i in docs) { ids.push('lc' + docs[i]._id); } + } + db.GetAllIdsOfType(ids, domain.id, 'lastconnect', function (err, docs) { + const lastConnects = {}; + if (docs != null) { for (var i in docs) { lastConnects[docs[i]._id] = docs[i]; } } - // Create a list of node ids and query them for last device connection time - const ids = [] - for (var i in command.nodeids) { ids.push('lc' + command.nodeids[i]); } - db.GetAllIdsOfType(ids, domain.id, 'lastconnect', function (err, docs) { - const lastConnects = {}; - if (docs != null) { for (var i in docs) { lastConnects[docs[i]._id] = docs[i]; } } + getDeviceDetailedInfo(command.nodeids, command.type, function (results, type) { + for (var i = 0; i < results.length; i++) { + // Remove any device system and network information is we do not have details rights to this device + if ((parent.GetNodeRights(user, results[i].node.meshid, results[i].node._id) & MESHRIGHT_DEVICEDETAILS) == 0) { + delete results[i].sys; delete results[i].net; + } - getDeviceDetailedInfo(command.nodeids, command.type, function (results, type) { - for (var i = 0; i < results.length; i++) { - // Remove any device system and network information is we do not have details rights to this device - if ((parent.GetNodeRights(user, results[i].node.meshid, results[i].node._id) & MESHRIGHT_DEVICEDETAILS) == 0) { - delete results[i].sys; delete results[i].net; + // Merge any last connection information + const lc = lastConnects['lc' + results[i].node._id]; + if (lc != null) { delete lc._id; delete lc.type; delete lc.meshid; delete lc.domain; results[i].lastConnect = lc; } + + // Remove any connectivity and power state information, that should not be in the database anyway. + // TODO: Find why these are sometimes saved in the db. + if (results[i].node.conn != null) { delete results[i].node.conn; } + if (results[i].node.pwr != null) { delete results[i].node.pwr; } + if (results[i].node.agct != null) { delete results[i].node.agct; } + if (results[i].node.cict != null) { delete results[i].node.cict; } + + // Add the connection state + var state = parent.parent.GetConnectivityState(results[i].node._id); + if (state) { + results[i].node.conn = state.connectivity; + results[i].node.pwr = state.powerState; + if ((state.connectivity & 1) != 0) { var agent = parent.wsagents[results[i].node._id]; if (agent != null) { results[i].node.agct = agent.connectTime; } } + + // Use the connection time of the CIRA/Relay connection + if ((state.connectivity & 2) != 0) { + var ciraConnection = parent.parent.mpsserver.GetConnectionToNode(results[i].node._id, null, true); + if ((ciraConnection != null) && (ciraConnection.tag != null)) { results[i].node.cict = ciraConnection.tag.connectTime; } + } + } + } - // Merge any last connection information - const lc = lastConnects['lc' + results[i].node._id]; - if (lc != null) { delete lc._id; delete lc.type;; delete lc.meshid; delete lc.domain; results[i].lastConnect = lc; } - } + var output = null; + if (type == 'csv') { + try { + // Create the CSV file + output = 'id,name,rname,host,icon,ip,osdesc,groupname,av,update,firewall,bitlocker,avdetails,tags,lastbootuptime,cpu,osbuild,biosDate,biosVendor,biosVersion,biosSerial,biosMode,boardName,boardVendor,boardVersion,productUuid,tpmversion,tpmmanufacturer,tpmmanufacturerversion,tpmisactivated,tpmisenabled,tpmisowned,totalMemory,agentOpenSSL,agentCommitDate,agentCommitHash,agentCompileTime,netIfCount,macs,addresses,lastConnectTime,lastConnectAddr\r\n'; + for (var i = 0; i < results.length; i++) { + const nodeinfo = results[i]; - var output = null; - if (type == 'csv') { - try { - // Create the CSV file - output = 'id,name,rname,host,icon,ip,osdesc,groupname,av,update,firewall,avdetails,cpu,osbuild,biosDate,biosVendor,biosVersion,boardName,boardVendor,boardVersion,productUuid,totalMemory,agentOpenSSL,agentCommitDate,agentCommitHash,agentCompileTime,netIfCount,macs,addresses,lastConnectTime,lastConnectAddr\r\n'; + // Node information + if (nodeinfo.node != null) { + const n = nodeinfo.node; + output += csvClean(n._id) + ',' + csvClean(n.name) + ',' + csvClean(n.rname ? n.rname : '') + ',' + csvClean(n.host ? n.host : '') + ',' + (n.icon ? n.icon : 1) + ',' + (n.ip ? n.ip : '') + ',' + (n.osdesc ? csvClean(n.osdesc) : '') + ',' + csvClean(parent.meshes[n.meshid].name); + if (typeof n.wsc == 'object') { + output += ',' + csvClean(n.wsc.antiVirus ? n.wsc.antiVirus : '') + ',' + csvClean(n.wsc.autoUpdate ? n.wsc.autoUpdate : '') + ',' + csvClean(n.wsc.firewall ? n.wsc.firewall : '') + } else { output += ',,,'; } + if (typeof n.volumes == 'object') { + var bitlockerdetails = '', firstbitlocker = true; + for (var a in n.volumes) { if (typeof n.volumes[a].protectionStatus !== 'undefined') { if (firstbitlocker) { firstbitlocker = false; } else { bitlockerdetails += '|'; } bitlockerdetails += a + '/' + n.volumes[a].volumeStatus; } } + output += ',' + csvClean(bitlockerdetails); + } else { + output += ','; + } + if (typeof n.av == 'object') { + var avdetails = '', firstav = true; + for (var a in n.av) { if (typeof n.av[a].product == 'string') { if (firstav) { firstav = false; } else { avdetails += '|'; } avdetails += (n.av[a].product + '/' + ((n.av[a].enabled) ? 'enabled' : 'disabled') + '/' + ((n.av[a].updated) ? 'updated' : 'notupdated')); } } + output += ',' + csvClean(avdetails); + } else { + output += ','; + } + if (typeof n.tags == 'object') { + var tagsdetails = '', firsttags = true; + for (var a in n.tags) { if (firsttags) { firsttags = false; } else { tagsdetails += '|'; } tagsdetails += n.tags[a]; } + output += ',' + csvClean(tagsdetails); + } else { + output += ','; + } + if (typeof n.lastbootuptime == 'number') { output += ',' + n.lastbootuptime; } else { output += ','; } + } else { + output += ',,,,,,,,,,,,,,,,,,,,'; + } + + // System infomation + if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows)) { + // Windows + output += ','; + if (nodeinfo.sys.hardware.windows.cpu && (nodeinfo.sys.hardware.windows.cpu.length > 0) && (typeof nodeinfo.sys.hardware.windows.cpu[0].Name == 'string')) { output += csvClean(nodeinfo.sys.hardware.windows.cpu[0].Name); } + output += ','; + if (nodeinfo.sys.hardware.windows.osinfo && (nodeinfo.sys.hardware.windows.osinfo.BuildNumber)) { output += csvClean(nodeinfo.sys.hardware.windows.osinfo.BuildNumber); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_date)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_date); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_vendor); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_version); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_serial)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_serial); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_mode)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_mode); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_name); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_vendor); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_version); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.identifiers.product_uuid); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.SpecVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.SpecVersion); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerId) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerId); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerVersion); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsActivated) { output += csvClean(nodeinfo.sys.hardware.tpm.IsActivated ? 'true' : 'false'); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsEnabled) { output += csvClean(nodeinfo.sys.hardware.tpm.IsEnabled ? 'true' : 'false'); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsOwned) { output += csvClean(nodeinfo.sys.hardware.tpm.IsOwned ? 'true' : 'false'); } + output += ','; + if (nodeinfo.sys.hardware.windows.memory) { + var totalMemory = 0; + for (var j in nodeinfo.sys.hardware.windows.memory) { + if (nodeinfo.sys.hardware.windows.memory[j].Capacity) { + if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'number') { totalMemory += nodeinfo.sys.hardware.windows.memory[j].Capacity; } + if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.windows.memory[j].Capacity); } + } + } + output += csvClean('' + totalMemory); + } + } else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.mobile)) { + // Mobile + output += ','; + output += ','; + output += ','; + output += ','; + output += ','; + if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.bootloader)) { output += csvClean(nodeinfo.sys.hardware.mobile.bootloader); } + output += ','; + output += ','; + output += ','; + if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.model)) { output += csvClean(nodeinfo.sys.hardware.mobile.model); } + output += ','; + if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.brand)) { output += csvClean(nodeinfo.sys.hardware.mobile.brand); } + output += ','; + output += ','; + if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.id)) { output += csvClean(nodeinfo.sys.hardware.mobile.id); } + output += ','; + output += ','; + output += ','; + output += ','; + output += ','; + output += ','; + output += ','; + } else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.linux)) { + // Linux + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.cpu_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.cpu_name); } + output += ',,'; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_date)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_date); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_vendor); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_version)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_version); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_serial)) { output += csvClean(nodeinfo.sys.hardware.linux.product_serial); } + else if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_serial)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_serial); } + output += ','; + if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_mode)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_mode); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_name)) { output += csvClean(nodeinfo.sys.hardware.linux.board_name); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.board_vendor); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_version)) { output += csvClean(nodeinfo.sys.hardware.linux.board_version); } + output += ','; + if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.linux.product_uuid); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.SpecVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.SpecVersion); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerId) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerId); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerVersion); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsActivated) { output += csvClean(nodeinfo.sys.hardware.tpm.IsActivated ? 'true' : 'false'); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsEnabled) { output += csvClean(nodeinfo.sys.hardware.tpm.IsEnabled ? 'true' : 'false'); } + output += ','; + if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsOwned) { output += csvClean(nodeinfo.sys.hardware.tpm.IsOwned ? 'true' : 'false'); } + output += ','; + if (nodeinfo.sys.hardware.linux.memory) { + if (nodeinfo.sys.hardware.linux.memory.Memory_Device) { + var totalMemory = 0; + for (var j in nodeinfo.sys.hardware.linux.memory.Memory_Device) { + if (nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size) { + if (typeof nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size == 'number') { totalMemory += nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size; } + if (typeof nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size); } + } + } + output += csvClean('' + (totalMemory * Math.pow(1024, 3))); + } + } + } else { + output += ',,,,,,,,,,,,,,,,,,'; + } + + // Agent information + if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.agentvers)) { + output += ','; + if (nodeinfo.sys.hardware.agentvers.openssl) { output += csvClean(nodeinfo.sys.hardware.agentvers.openssl); } + output += ','; + if (nodeinfo.sys.hardware.agentvers.commitDate) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitDate); } + output += ','; + if (nodeinfo.sys.hardware.agentvers.commitHash) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitHash); } + output += ','; + if (nodeinfo.sys.hardware.agentvers.compileTime) { output += csvClean(nodeinfo.sys.hardware.agentvers.compileTime); } + } else { + output += ',,,,'; + } + + // Network interfaces + if ((nodeinfo.net) && (nodeinfo.net.netif2)) { + output += ','; + output += Object.keys(nodeinfo.net.netif2).length; // Interface count + var macs = [], addresses = []; + for (var j in nodeinfo.net.netif2) { + if (Array.isArray(nodeinfo.net.netif2[j])) { + for (var k = 0; k < nodeinfo.net.netif2[j].length; k++) { + if (typeof nodeinfo.net.netif2[j][k].mac == 'string') { macs.push(nodeinfo.net.netif2[j][k].mac); } + if (typeof nodeinfo.net.netif2[j][k].address == 'string') { addresses.push(nodeinfo.net.netif2[j][k].address); } + } + } + } + output += ','; + output += csvClean(macs.join(' ')); // MACS + output += ','; + output += csvClean(addresses.join(' ')); // Addresses + } else { + output += ',,,'; + } + + // Last connection information + if (nodeinfo.lastConnect) { + output += ','; + if (nodeinfo.lastConnect.time) { + // Last connection time + if ((typeof command.l == 'string') && (typeof command.tz == 'string')) { + output += csvClean(new Date(nodeinfo.lastConnect.time).toLocaleString(command.l, { timeZone: command.tz })) + } else { + output += nodeinfo.lastConnect.time; + } + } + output += ','; + if (typeof nodeinfo.lastConnect.addr == 'string') { output += csvClean(nodeinfo.lastConnect.addr); } // Last connection address and port + } else { + output += ',,'; + } + + output += '\r\n'; + } + } catch (ex) { console.log(ex); } + } else { + // Create the JSON file + + // Add the device group name to each device for (var i = 0; i < results.length; i++) { const nodeinfo = results[i]; - - // Node information - if (nodeinfo.node != null) { - const n = nodeinfo.node; - output += csvClean(n._id) + ',' + csvClean(n.name) + ',' + csvClean(n.rname ? n.rname : '') + ',' + csvClean(n.host ? n.host : '') + ',' + (n.icon ? n.icon : 1) + ',' + (n.ip ? n.ip : '') + ',' + (n.osdesc ? csvClean(n.osdesc) : '') + ',' + csvClean(parent.meshes[n.meshid].name); - if (typeof n.wsc == 'object') { - output += ',' + csvClean(n.wsc.antiVirus ? n.wsc.antiVirus : '') + ',' + csvClean(n.wsc.autoUpdate ? n.wsc.autoUpdate : '') + ',' + csvClean(n.wsc.firewall ? n.wsc.firewall : '') - } else { output += ',,,'; } - if (typeof n.av == 'object') { - var avdetails = '', firstav = true; - for (var a in n.av) { if (typeof n.av[a].product == 'string') { if (firstav) { firstav = false; } else { avdetails += '|'; } avdetails += (n.av[a].product + '/' + ((n.av[a].enabled) ? 'enabled' : 'disabled') + '/' + ((n.av[a].updated) ? 'updated' : 'notupdated')); } } - output += ',' + csvClean(avdetails); - } - else { output += ','; } - } else { - output += ',,,,,,,,,,,'; + if (nodeinfo.node) { + const mesh = parent.meshes[nodeinfo.node.meshid]; + if (mesh) { results[i].node.groupname = mesh.name; } } - - // System infomation - if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows) && (nodeinfo.sys.hardware.windows)) { - // Windows - output += ','; - if (nodeinfo.sys.hardware.windows.cpu && (nodeinfo.sys.hardware.windows.cpu.length > 0) && (typeof nodeinfo.sys.hardware.windows.cpu[0].Name == 'string')) { output += csvClean(nodeinfo.sys.hardware.windows.cpu[0].Name); } - output += ','; - if (nodeinfo.sys.hardware.windows.osinfo && (nodeinfo.sys.hardware.windows.osinfo.BuildNumber)) { output += csvClean(nodeinfo.sys.hardware.windows.osinfo.BuildNumber); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_date)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_date); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_vendor); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_version); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_name); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_vendor); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_version); } - output += ','; - if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.identifiers.product_uuid); } - output += ','; - if (nodeinfo.sys.hardware.windows.memory) { - var totalMemory = 0; - for (var j in nodeinfo.sys.hardware.windows.memory) { - if (nodeinfo.sys.hardware.windows.memory[j].Capacity) { - if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'number') { totalMemory += nodeinfo.sys.hardware.windows.memory[j].Capacity; } - if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.windows.memory[j].Capacity); } - } - } - output += csvClean('' + totalMemory); - } - } else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.mobile)) { - // Mobile - output += ','; - output += ','; - output += ','; - output += ','; - output += ','; - if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.bootloader)) { output += csvClean(nodeinfo.sys.hardware.mobile.bootloader); } - output += ','; - if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.model)) { output += csvClean(nodeinfo.sys.hardware.mobile.model); } - output += ','; - if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.brand)) { output += csvClean(nodeinfo.sys.hardware.mobile.brand); } - output += ','; - output += ','; - if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.id)) { output += csvClean(nodeinfo.sys.hardware.mobile.id); } - output += ','; - } else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows) && (nodeinfo.sys.hardware.linux)) { - // Linux - output += ','; - output += ','; - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_date)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_date); } - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_vendor); } - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_version)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_version); } - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_name)) { output += csvClean(nodeinfo.sys.hardware.linux.board_name); } - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.board_vendor); } - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_version)) { output += csvClean(nodeinfo.sys.hardware.linux.board_version); } - output += ','; - if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.linux.product_uuid); } - output += ','; - } else { - output += ',,,,,,,,,,'; - } - - // Agent information - if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.agentvers)) { - output += ','; - if (nodeinfo.sys.hardware.agentvers.openssl) { output += csvClean(nodeinfo.sys.hardware.agentvers.openssl); } - output += ','; - if (nodeinfo.sys.hardware.agentvers.commitDate) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitDate); } - output += ','; - if (nodeinfo.sys.hardware.agentvers.commitHash) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitHash); } - output += ','; - if (nodeinfo.sys.hardware.agentvers.compileTime) { output += csvClean(nodeinfo.sys.hardware.agentvers.compileTime); } - } else { - output += ',,,,'; - } - - // Network interfaces - if ((nodeinfo.net) && (nodeinfo.net.netif2)) { - output += ','; - output += Object.keys(nodeinfo.net.netif2).length; // Interface count - var macs = [], addresses = []; - for (var j in nodeinfo.net.netif2) { - if (Array.isArray(nodeinfo.net.netif2[j])) { - for (var k = 0; k < nodeinfo.net.netif2[j].length; k++) { - if (typeof nodeinfo.net.netif2[j][k].mac == 'string') { macs.push(nodeinfo.net.netif2[j][k].mac); } - if (typeof nodeinfo.net.netif2[j][k].address == 'string') { addresses.push(nodeinfo.net.netif2[j][k].address); } - } - } - } - output += ','; - output += csvClean(macs.join(' ')); // MACS - output += ','; - output += csvClean(addresses.join(' ')); // Addresses - } else { - output += ',,,'; - } - - // Last connection information - if (nodeinfo.lastConnect) { - output += ','; - if (nodeinfo.lastConnect.time) { - // Last connection time - if ((typeof command.l == 'string') && (typeof command.tz == 'string')) { - output += csvClean(new Date(nodeinfo.lastConnect.time).toLocaleString(command.l, { timeZone: command.tz })) - } else { - output += nodeinfo.lastConnect.time; - } - } - output += ','; - if (typeof nodeinfo.lastConnect.addr == 'string') { output += csvClean(nodeinfo.lastConnect.addr); } // Last connection address and port - } else { - output += ',,'; - } - - output += '\r\n'; } - } catch (ex) { console.log(ex); } - } else { - // Create the JSON file - // Add the device group name to each device - for (var i = 0; i < results.length; i++) { - const nodeinfo = results[i]; - if (nodeinfo.node) { - const mesh = parent.meshes[nodeinfo.node.meshid]; - if (mesh) { results[i].node.groupname = mesh.name; } - } + output = JSON.stringify(results, null, 2); } - - output = JSON.stringify(results, null, 2); - } - try { ws.send(JSON.stringify({ action: 'getDeviceDetails', data: output, type: type })); } catch (ex) { } + try { ws.send(JSON.stringify({ action: 'getDeviceDetails', data: output, type: type })); } catch (ex) { } + }); }); }); - break; } case 'endDesktopMultiplex': { @@ -5269,6 +5564,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use 'serverclearerrorlog': serverCommandServerClearErrorLog, 'serverconsole': serverCommandServerConsole, 'servererrors': serverCommandServerErrors, + 'serverconfig': serverCommandServerConfig, 'serverstats': serverCommandServerStats, 'servertimelinestats': serverCommandServerTimelineStats, 'serverupdate': serverCommandServerUpdate, @@ -5312,11 +5608,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use 'dupagents': [serverUserCommandDupAgents, ""], 'email': [serverUserCommandEmail, ""], 'emailnotifications': [serverUserCommandEmailNotifications, ""], + 'msgnotifications': [serverUserCommandMessageNotifications, ""], 'firebase': [serverUserCommandFirebase, ""], 'heapdump': [serverUserCommandHeapDump, ""], 'heapdump2': [serverUserCommandHeapDump2, ""], 'help': [serverUserCommandHelp, ""], - 'info': [serverUserCommandInfo, "Returns the most immidiatly useful information about this server, including MeshCentral and NodeJS versions. This is often information required to file a bug."], + 'info': [serverUserCommandInfo, "Returns the most immidiatly useful information about this server, including MeshCentral and NodeJS versions. This is often information required to file a bug. Optionally use info h for human readable form."], 'le': [serverUserCommandLe, ""], 'lecheck': [serverUserCommandLeCheck, ""], 'leevents': [serverUserCommandLeEvents, ""], @@ -5353,7 +5650,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (common.validateString(command.nodeid, 1, 1024) == false) { err = 'Invalid nodeid'; } // Check the nodeid else if (common.validateInt(command.rights) == false) { err = 'Invalid rights'; } // Device rights must be an integer else if ((command.rights & 7) != 0) { err = 'Invalid rights'; } // EDITMESH, MANAGEUSERS or MANAGECOMPUTERS rights can't be assigned to a user to device link - else if ((common.validateStrArray(command.usernames, 1, 64) == false) && (common.validateStrArray(command.userids, 1, 128) == false)) { err = 'Invalid usernames'; } // Username is between 1 and 64 characters + else if ((common.validateStrArray(command.usernames, 1, 128) == false) && (common.validateStrArray(command.userids, 1, 128) == false)) { err = 'Invalid usernames'; } // Username is between 1 and 128 characters else { if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; } else if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain @@ -5500,7 +5797,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use try { if (common.validateString(command.meshid, 8, 134) == false) { err = 'Invalid groupid'; } // Check the meshid else if (common.validateInt(command.meshadmin) == false) { err = 'Invalid group rights'; } // Mesh rights must be an integer - else if ((common.validateStrArray(command.usernames, 1, 64) == false) && (common.validateStrArray(command.userids, 1, 128) == false)) { err = 'Invalid usernames'; } // Username is between 1 and 64 characters + else if ((common.validateStrArray(command.usernames, 1, 128) == false) && (common.validateStrArray(command.userids, 1, 128) == false)) { err = 'Invalid usernames'; } // Username is between 1 and 128 characters else { if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; } mesh = parent.meshes[command.meshid]; @@ -5831,7 +6128,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use try { if ((user.siteadmin & SITERIGHT_USERGROUPS) == 0) { err = 'Permission denied'; } else if (common.validateString(command.ugrpid, 1, 1024) == false) { err = 'Invalid groupid'; } // Check the meshid - else if (common.validateStrArray(command.usernames, 1, 64) == false) { err = 'Invalid usernames'; } // Username is between 1 and 64 characters + else if (common.validateStrArray(command.usernames, 1, 128) == false) { err = 'Invalid usernames'; } // Username is between 1 and 128 characters else { var ugroupidsplit = command.ugrpid.split('/'); if ((ugroupidsplit.length != 3) || (ugroupidsplit[0] != 'ugrp') || ((obj.crossDomain !== true) && (ugroupidsplit[1] != domain.id))) { err = 'Invalid groupid'; } @@ -5998,7 +6295,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use parent.db.SetUser(user); // Event the change - var message = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id, msgid: 2, msgArgs: [(oldlang ? oldlang : 'default'), (user.lang ? user.lang : 'default')] }; + var message = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id, msgid: 3, msgArgs: ['', (oldlang ? oldlang : 'default'), (user.lang ? user.lang : 'default')] }; if (db.changeStream) { message.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come. message.msg = 'Changed language from ' + (oldlang ? oldlang : 'default') + ' to ' + (user.lang ? user.lang : 'default'); @@ -6119,6 +6416,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (command.nodeid) { cookieContent.nodeid = command.nodeid; } if (command.tcpaddr) { cookieContent.tcpaddr = command.tcpaddr; } // Indicates the browser want the agent to TCP connect to a remote address if (command.tcpport) { cookieContent.tcpport = command.tcpport; } // Indicates the browser want the agent to TCP connect to a remote port + if (command.tag == 'novnc') { cookieContent.p = 12; } // If tag is novnc we must encode a protocol for meshrelay logging if (node.mtype == 3) { cookieContent.lc = 1; command.localRelay = true; } // Indicate this is for a local connection command.cookie = parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey); command.trustedCert = parent.isTrustedCert(domain); @@ -6167,6 +6465,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use delete doc.type; delete doc.domain; delete doc._id; + + // If this is not a device group admin users, don't send any BitLocker recovery passwords + if ((rights != MESHRIGHT_ADMIN) && (doc.hardware) && (doc.hardware.windows) && (doc.hardware.windows.volumes)) { + for (var i in doc.hardware.windows.volumes) { delete doc.hardware.windows.volumes[i].recoveryPassword; } + } + if (command.nodeinfo === true) { doc.node = node; doc.rights = rights; } obj.send(doc); } else { @@ -6425,7 +6729,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use const manageAllDeviceGroups = ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0)); if ((command.devGroup != null) && (manageAllDeviceGroups == false) && ((user.links == null) || (user.links[command.devGroup] == null))) return; // Asking for a device group that is not allowed - const msgIdFilter = [5, 10, 11, 12, 122, 123, 124, 125, 126]; + const msgIdFilter = [5, 10, 11, 12, 122, 123, 124, 125, 126, 144]; switch (command.type) { case 1: { remoteSessionReport(command, manageAllDeviceGroups, msgIdFilter); @@ -6480,6 +6784,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use fs.readFile(parent.parent.getConfigFilePath('mesherrors.txt'), 'utf8', function (err, data) { obj.send({ action: 'servererrors', data: data }); }); } + function serverCommandServerConfig(command) { + // Load the server config.json. This is a sensitive file so care must be taken to only send to trusted administrators. + if (userHasSiteUpdate() && (domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.config === true))) { + const configFilePath = common.joinPath(parent.parent.datapath, (parent.parent.args.configfile ? parent.parent.args.configfile : 'config.json')); + fs.readFile(configFilePath, 'utf8', function (err, data) { obj.send({ action: 'serverconfig', data: data }); }); + } + } + function serverCommandServerStats(command) { // Only accept if the "My Server" tab is allowed for this domain if (domain.myserver === false) return; @@ -6708,6 +7020,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((command.service == 32) && ((parent.parent.msgserver.providers & 32) != 0)) { handle = 'pushover:' + command.handle; } if ((command.service == 64) && ((parent.parent.msgserver.providers & 64) != 0)) { handle = 'ntfy:' + command.handle; } if ((command.service == 128) && ((parent.parent.msgserver.providers & 128) != 0)) { handle = 'zulip:' + command.handle; } + if ((command.service == 256) && ((parent.parent.msgserver.providers & 256) != 0)) { handle = 'slack:' + command.handle; } if (handle == null) return; // Send a verification message @@ -6854,6 +7167,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((parent.parent.msgserver.providers & 32) != 0) { r.push("Usage: MSG \"pushover:[userkey]\" \"Message\"."); } if ((parent.parent.msgserver.providers & 64) != 0) { r.push("Usage: MSG \"ntfy:[topic]\" \"Message\"."); } if ((parent.parent.msgserver.providers & 128) != 0) { r.push("Usage: MSG \"zulip:[topic]\" \"Message\"."); } + if ((parent.parent.msgserver.providers & 256) != 0) { r.push("Usage: MSG \"slack:[webhook]\" \"Message\"."); } cmdData.result = r.join('\r\n'); } else { parent.parent.msgserver.sendMessage(cmdData.cmdargs['_'][0], cmdData.cmdargs['_'][1], domain, function (status, msg) { @@ -6892,7 +7206,23 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use x += ' ' + info.mn + ', ' + info.nn + ', c:' + (info.c ? info.c : 0) + ', d:' + (info.d ? info.d : 0) + '\r\n'; } } - cmdData.result = ((x == '')?'None':x); + cmdData.result = ((x == '') ? 'None' : x); + } + } + + function serverUserCommandMessageNotifications(cmdData) { + if (parent.parent.msgserver == null) { + cmdData.result = "No messaging service enabled."; + } else { + var x = ''; + for (var userid in parent.parent.msgserver.deviceNotifications) { + x += userid + '\r\n'; + for (var nodeid in parent.parent.msgserver.deviceNotifications[userid].nodes) { + const info = parent.parent.msgserver.deviceNotifications[userid].nodes[nodeid]; + x += ' ' + info.mn + ', ' + info.nn + ', c:' + (info.c ? info.c : 0) + ', d:' + (info.d ? info.d : 0) + '\r\n'; + } + } + cmdData.result = ((x == '') ? 'None' : x); } } @@ -6941,13 +7271,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use for (var i in parent.badLoginTable) { badLoginCount++; if (typeof parent.badLoginTable[i] == 'number') { - cmdData.result += "Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n"; + cmdData.result += (i + " - Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n"); } else { - if (parent.badLoginTable[i].length > 1) { - cmdData.result += (i + ' - ' + parent.badLoginTable[i].length + " records\r\n"); - } else { - cmdData.result += (i + ' - ' + parent.badLoginTable[i].length + " record\r\n"); - } + cmdData.result += (i + ' - ' + parent.badLoginTable[i].length + " attempt(s) until Cooloff ban\r\n"); } } if (badLoginCount == 0) { cmdData.result += 'No bad logins.'; } @@ -7233,7 +7559,26 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } function serverUserCommandInfo(cmdData) { - var info = {}; + function convertSeconds (s, form) { + if (!['long', 'shortprecise'].includes(form)) { + form = 'shortprecise'; + } + let t = {}, r = ''; + t.d = Math.floor(s / (24 * 3600)); + s %= 24 * 3600; + t.h= Math.floor(s / 3600); + s %= 3600; + t.m = Math.floor(s / 60); + t.s =(s%60).toFixed(0); + if ( form == 'long') { + r = t.d + ((t.d == 1) ? ' day, ' : ' days, ') + t.h + ((t.h == 1) ? ' hour, ' : ' hours, ') + t.m + ((t.m == 1) ? ' minute, ' : ' minutes, ') + t.s+ ((t.s == 1) ? ' second' : ' seconds'); + } else if (form == 'shortprecise') { + r = String(t.d).padStart(2, '0') + ':' + String(t.h).padStart(2, '0') + ':' + String(t.m).padStart(2, '0') + ':' + String((s%60).toFixed(2)).padStart(5, '0') + 's'; + } + return r; + } + var info = {}, arg = null, t = {}, r = ''; + if ((cmdData.cmdargs['_'] != null) && (cmdData.cmdargs['_'][0] != null)) { arg = cmdData.cmdargs['_'][0].toLowerCase(); } try { info.meshVersion = 'v' + parent.parent.currentVer; } catch (ex) { } try { info.nodeVersion = process.version; } catch (ex) { } try { info.runMode = (["Hybrid (LAN + WAN) mode", "WAN mode", "LAN mode"][(args.lanonly ? 2 : (args.wanonly ? 1 : 0))]); } catch (ex) { } @@ -7245,9 +7590,24 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use try { info.platform = process.platform; } catch (ex) { } try { info.arch = process.arch; } catch (ex) { } try { info.pid = process.pid; } catch (ex) { } - try { info.uptime = process.uptime(); } catch (ex) { } - try { info.cpuUsage = process.cpuUsage(); } catch (ex) { } - try { info.memoryUsage = process.memoryUsage(); } catch (ex) { } + if (arg == 'h') { + try { + info.uptime = convertSeconds(process.uptime(), 'long'); + info.cpuUsage = { + system: (convertSeconds(process.cpuUsage().system /1000000)), + user: (convertSeconds(process.cpuUsage().user /1000000)) + } + info.memoryUsage = {}; + for (const [key,value] of Object.entries(process.memoryUsage())){ + info.memoryUsage[key] = ([value]/1048576).toFixed(2) + 'Mb'; + } + } catch (ex) { } + } + else { + try { info.uptime = process.uptime(); } catch (ex) { } + try { info.cpuUsage = process.cpuUsage(); } catch (ex) { } + try { info.memoryUsage = process.memoryUsage(); } catch (ex) { } + } try { info.warnings = parent.parent.getServerWarnings(); } catch (ex) { console.log(ex); } try { info.allDevGroupManagers = parent.parent.config.settings.managealldevicegroups; } catch (ex) { } try { if (process.traceDeprecation == true) { info.traceDeprecation = true; } } catch (ex) { } @@ -7350,8 +7710,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use cmdData.result += 'Record: ' + parent.parent.recordpath + '\r\n'; cmdData.result += 'WebPublic: ' + parent.parent.webPublicPath + '\r\n'; cmdData.result += 'WebViews: ' + parent.parent.webViewsPath + '\r\n'; - if (parent.parent.webViewsOverridePath) { cmdData.result += 'XWebPublic: ' + parent.parent.webViewsOverridePath + '\r\n'; } - if (parent.parent.webViewsOverridePath) { cmdData.result += 'XWebViews: ' + parent.parent.webPublicOverridePath + '\r\n'; } + cmdData.result += 'WebEmails: ' + parent.parent.webEmailsPath + '\r\n'; + if (parent.parent.webPublicOverridePath) { cmdData.result += 'XWebPublic: ' + parent.parent.webPublicOverridePath + '\r\n'; } + if (parent.parent.webViewsOverridePath) { cmdData.result += 'XWebViews: ' + parent.parent.webViewsOverridePath + '\r\n'; } + if (parent.parent.webEmailsOverridePath) { cmdData.result += 'XWebEmails: ' + parent.parent.webEmailsOverridePath + '\r\n'; } + if (domain.webpublicpath) { cmdData.result += 'DomainWebPublic: ' + domain.webpublicpath + '\r\n'; } + if (domain.webviewspath) { cmdData.result += 'DomainWebViews: ' + domain.webviewspath + '\r\n'; } + if (domain.webemailspath) { cmdData.result += 'DomainWebEmails: ' + domain.webemailspath + '\r\n'; } } function serverUserCommandMigrationAgents(cmdData) { @@ -7406,10 +7771,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } function serverUserCommandAutoBackup(cmdData) { - var backupResult = parent.db.performBackup(function (msg) { + cmdData.result = parent.db.performBackup(function (msg) { try { ws.send(JSON.stringify({ action: 'serverconsole', value: msg, tag: cmdData.command.tag })); } catch (ex) { } }); - if (backupResult == 0) { cmdData.result = 'Starting auto-backup...'; } else { cmdData.result = 'Backup alreay in progress.'; } } function serverUserCommandBackupConfig(cmdData) { @@ -7514,6 +7878,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Session length if (((docs[i].msgid >= 10) && (docs[i].msgid <= 12)) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[3] == 'number')) { entry.length = docs[i].msgArgs[3]; } else if ((docs[i].msgid >= 122) && (docs[i].msgid <= 126) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[0] == 'number')) { entry.length = docs[i].msgArgs[0]; } + else if ((docs[i].msgid == 144) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[1] == 'number')) { entry.length = docs[i].msgArgs[1]; } if (command.groupBy == 1) { // Add entry to per user if (data.groups[docs[i].userid] == null) { data.groups[docs[i].userid] = { entries: [] }; } @@ -7580,6 +7945,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Session length if (((docs[i].msgid >= 10) && (docs[i].msgid <= 12)) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[3] == 'number')) { userEntry.length += docs[i].msgArgs[3]; } else if ((docs[i].msgid >= 122) && (docs[i].msgid <= 126) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[0] == 'number')) { userEntry.length += docs[i].msgArgs[0]; } + else if ((docs[i].msgid == 144) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[1] == 'number')) { userEntry.length += docs[i].msgArgs[1]; } // Set the user entry userEntries[docs[i].userid] = userEntry; @@ -7731,42 +8097,46 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use parent.common.unEscapeAllLinksFieldName(docs); var results = [], resultPendingCount = 0; - for (i in docs) { - // Check device links, if a link points to an unknown user, remove it. - parent.cleanDevice(docs[i]); + if (docs.length == 0) { // no results return blank array + func(docs, type); + } else { + for (i in docs) { + // Check device links, if a link points to an unknown user, remove it. + parent.cleanDevice(docs[i]); - // Fetch the node from the database - resultPendingCount++; - const getNodeFunc = function (node, rights, visible) { - if ((node != null) && (visible == true)) { - const getNodeSysInfoFunc = function (err, docs) { - const getNodeNetInfoFunc = function (err, docs) { - var netinfo = null; - if ((err == null) && (docs != null) && (docs.length == 1)) { netinfo = docs[0]; } - resultPendingCount--; - getNodeNetInfoFunc.results.push({ node: parent.CloneSafeNode(getNodeNetInfoFunc.node), sys: getNodeNetInfoFunc.sysinfo, net: netinfo }); - if (resultPendingCount == 0) { func(getNodeFunc.results, type); } + // Fetch the node from the database + resultPendingCount++; + const getNodeFunc = function (node, rights, visible) { + if ((node != null) && (visible == true)) { + const getNodeSysInfoFunc = function (err, docs) { + const getNodeNetInfoFunc = function (err, docs) { + var netinfo = null; + if ((err == null) && (docs != null) && (docs.length == 1)) { netinfo = docs[0]; } + resultPendingCount--; + getNodeNetInfoFunc.results.push({ node: parent.CloneSafeNode(getNodeNetInfoFunc.node), sys: getNodeNetInfoFunc.sysinfo, net: netinfo }); + if (resultPendingCount == 0) { func(getNodeFunc.results, type); } + } + getNodeNetInfoFunc.results = getNodeSysInfoFunc.results; + getNodeNetInfoFunc.nodeid = getNodeSysInfoFunc.nodeid; + getNodeNetInfoFunc.node = getNodeSysInfoFunc.node; + if ((err == null) && (docs != null) && (docs.length == 1)) { getNodeNetInfoFunc.sysinfo = docs[0]; } + + // Query the database for network information + db.Get('if' + getNodeSysInfoFunc.nodeid, getNodeNetInfoFunc); } - getNodeNetInfoFunc.results = getNodeSysInfoFunc.results; - getNodeNetInfoFunc.nodeid = getNodeSysInfoFunc.nodeid; - getNodeNetInfoFunc.node = getNodeSysInfoFunc.node; - if ((err == null) && (docs != null) && (docs.length == 1)) { getNodeNetInfoFunc.sysinfo = docs[0]; } + getNodeSysInfoFunc.results = getNodeFunc.results; + getNodeSysInfoFunc.nodeid = getNodeFunc.nodeid; + getNodeSysInfoFunc.node = node; - // Query the database for network information - db.Get('if' + getNodeSysInfoFunc.nodeid, getNodeNetInfoFunc); - } - getNodeSysInfoFunc.results = getNodeFunc.results; - getNodeSysInfoFunc.nodeid = getNodeFunc.nodeid; - getNodeSysInfoFunc.node = node; - - // Query the database for system information - db.Get('si' + getNodeFunc.nodeid, getNodeSysInfoFunc); - } else { resultPendingCount--; } - if (resultPendingCount == 0) { func(getNodeFunc.results.join('\r\n'), type); } + // Query the database for system information + db.Get('si' + getNodeFunc.nodeid, getNodeSysInfoFunc); + } else { resultPendingCount--; } + if (resultPendingCount == 0) { func(getNodeFunc.results.join('\r\n'), type); } + } + getNodeFunc.results = results; + getNodeFunc.nodeid = docs[i]._id; + parent.GetNodeWithRights(domain, user, docs[i]._id, getNodeFunc); } - getNodeFunc.results = results; - getNodeFunc.nodeid = docs[i]._id; - parent.GetNodeWithRights(domain, user, docs[i]._id, getNodeFunc); } }); } else { @@ -7964,11 +8334,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var email2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.email2factor != false)) && (domain.mailserver != null)); var sms2fa = ((parent.parent.smsserver != null) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false))); var msg2fa = ((parent.parent.msgserver != null) && (parent.parent.msgserver.providers != 0) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false))); + var duo2fa = ((typeof domain.passwordrequirements != 'object') || (typeof domain.passwordrequirements.duo2factor == 'object')); var authFactorCount = 0; if (typeof user.otpsecret == 'string') { authFactorCount++; } // Authenticator time factor if (email2fa && (user.otpekey != null)) { authFactorCount++; } // EMail factor if (sms2fa && (user.phone != null)) { authFactorCount++; } // SMS factor if (msg2fa && (user.msghandle != null)) { authFactorCount++; } // Messaging factor + if (duo2fa && (user.otpduo != null)) { authFactorCount++; } // Duo authentication factor if (user.otphkeys != null) { authFactorCount += user.otphkeys.length; } // FIDO hardware factor if ((authFactorCount > 0) && (user.otpkeys != null)) { authFactorCount++; } // Backup keys return authFactorCount; diff --git a/monitoring.js b/monitoring.js new file mode 100644 index 00000000..ffb03da7 --- /dev/null +++ b/monitoring.js @@ -0,0 +1,117 @@ +/** +* @description MeshCentral monitoring module +* @author Simon Smith +* @license Apache-2.0 +* @version v0.0.1 +*/ + +"use strict"; + +module.exports.CreateMonitoring = function (parent, args) { + var obj = {}; + obj.args = args; + obj.parent = parent; + obj.express = require('express'); + obj.app = obj.express(); + obj.prometheus = null; + if (args.compression !== false) { obj.app.use(require('compression')()); } + obj.app.disable('x-powered-by'); + obj.counterMetrics = { // Counter Metrics always start at 0 and increase but never decrease + RelayErrors: { description: "Relay Errors" }, // parent.webserver.relaySessionErrorCount + UnknownGroup: { description: "Unknown Group" }, // meshDoesNotExistCount + InvalidPKCSsignature: { description: "Invalid PKCS signature" }, // invalidPkcsSignatureCount + InvalidRSAsignature: { description: "Invalid RSA signature" }, // invalidRsaSignatureCount + InvalidJSON: { description: "Invalid JSON" }, // invalidJsonCount + UnknownAction: { description: "Unknown Action" }, // unknownAgentActionCount + BadWebCertificate: { description: "Bad Web Certificate" }, // agentBadWebCertHashCount + BadSignature: { description: "Bad Signature" }, // (agentBadSignature1Count + agentBadSignature2Count) + MaxSessionsReached: { description: "Max Sessions Reached" }, // agentMaxSessionHoldCount + UnknownDeviceGroup: { description: "Unknown Device Group" }, // (invalidDomainMeshCount + invalidDomainMesh2Count) + InvalidDeviceGroupType: { description: "Invalid Device Group Type" }, // invalidMeshTypeCount + DuplicateAgent: { description: "Duplicate Agent" }, // duplicateAgentCount + blockedUsers: { description: "Blocked Users" }, // blockedUsers + blockedAgents: { description: "Blocked Agents" }, // blockedAgents + }; + obj.gaugeMetrics = { // Gauge Metrics always start at 0 and can increase and decrease + ConnectedIntelAMT: { description: "Connected Intel AMT" }, // parent.mpsserver.ciraConnections[i].length + UserAccounts: { description: "User Accounts" }, // Object.keys(parent.webserver.users).length + DeviceGroups: { description: "Device Groups" }, // parent.webserver.meshes (ONLY WHERE deleted=null) + AgentSessions: { description: "Agent Sessions" }, // Object.keys(parent.webserver.wsagents).length + ConnectedUsers: { description: "Connected Users" }, // Object.keys(parent.webserver.wssessions).length + UsersSessions: { description: "Users Sessions" }, // Object.keys(parent.webserver.wssessions2).length + RelaySessions: { description: "Relay Sessions" }, // parent.webserver.relaySessionCount + RelayCount: { description: "Relay Count" } // Object.keys(parent.webserver.wsrelays).length30bb4fb74dfb758d36be52a7 + } + obj.collectors = []; + if (parent.config.settings.prometheus != null) { // Create Prometheus Monitoring Endpoint + if ((typeof parent.config.settings.prometheus == 'number') && ((parent.config.settings.prometheus < 1) || (parent.config.settings.prometheus > 65535))) { + console.log('Promethus port number is invalid, Prometheus metrics endpoint has be disabled'); + delete parent.config.settings.prometheus; + } else { + const port = ((typeof parent.config.settings.prometheus == 'number') ? parent.config.settings.prometheus : 9464); + obj.prometheus = require('prom-client'); + const collectDefaultMetrics = obj.prometheus.collectDefaultMetrics; + collectDefaultMetrics(); + for (const key in obj.gaugeMetrics) { + obj.gaugeMetrics[key].prometheus = new obj.prometheus.Gauge({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.gaugeMetrics[key].description }); + } + for (const key in obj.counterMetrics) { + obj.counterMetrics[key].prometheus = new obj.prometheus.Counter({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.counterMetrics[key].description }); + } + obj.app.get('/', function (req, res) { res.send('MeshCentral Prometheus server.'); }); + obj.app.listen(port, function () { + console.log('MeshCentral Prometheus server running on port ' + port + '.'); + obj.parent.updateServerState('prometheus-port', port); + }); + obj.app.get('/metrics', async (req, res) => { + try { + // Count the number of device groups that are not deleted + var activeDeviceGroups = 0; + for (var i in parent.webserver.meshes) { if (parent.webserver.meshes[i].deleted == null) { activeDeviceGroups++; } } // This is not ideal for performance, we want to dome something better. + var gauges = { + UserAccounts: Object.keys(parent.webserver.users).length, + DeviceGroups: activeDeviceGroups, + AgentSessions: Object.keys(parent.webserver.wsagents).length, + ConnectedUsers: Object.keys(parent.webserver.wssessions).length, + UsersSessions: Object.keys(parent.webserver.wssessions2).length, + RelaySessions: parent.webserver.relaySessionCount, + RelayCount: Object.keys(parent.webserver.wsrelays).length, + ConnectedIntelAMT: 0 + }; + if (parent.mpsserver != null) { + for (var i in parent.mpsserver.ciraConnections) { + gauges.ConnectedIntelAMT += parent.mpsserver.ciraConnections[i].length; + } + } + for (const key in gauges) { obj.gaugeMetrics[key].prometheus.set(gauges[key]); } + // Take a look at agent errors + var agentstats = parent.webserver.getAgentStats(); + const counters = { + RelayErrors: parent.webserver.relaySessionErrorCount, + UnknownGroup: agentstats.meshDoesNotExistCount, + InvalidPKCSsignature: agentstats.invalidPkcsSignatureCount, + InvalidRSAsignature: agentstats.invalidRsaSignatureCount, + InvalidJSON: agentstats.invalidJsonCount, + UnknownAction: agentstats.unknownAgentActionCount, + BadWebCertificate: agentstats.agentBadWebCertHashCount, + BadSignature: (agentstats.agentBadSignature1Count + agentstats.agentBadSignature2Count), + MaxSessionsReached: agentstats.agentMaxSessionHoldCount, + UnknownDeviceGroup: (agentstats.invalidDomainMeshCount + agentstats.invalidDomainMesh2Count), + InvalidDeviceGroupType: (agentstats.invalidMeshTypeCount + agentstats.invalidMeshType2Count), + DuplicateAgent: agentstats.duplicateAgentCount, + blockedUsers: parent.webserver.blockedUsers, + blockedAgents: parent.webserver.blockedAgents + }; + for (const key in counters) { obj.counterMetrics[key].prometheus.reset(); obj.counterMetrics[key].prometheus.inc(counters[key]); } + res.set('Content-Type', obj.prometheus.register.contentType); + await Promise.all(obj.collectors.map((collector) => (collector(req, res)))); + res.end(await obj.prometheus.register.metrics()); + } catch (ex) { + console.log(ex); + res.status(500).end(); + } + }); + } + } + return obj; +} \ No newline at end of file diff --git a/mpsserver.js b/mpsserver.js index 515069bb..ec5a8312 100644 --- a/mpsserver.js +++ b/mpsserver.js @@ -48,7 +48,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_CHACHA20_POLY1305_SHA256", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1 }, onConnection) } else { // Lower security MPS in order to support older Intel AMT CIRA connections, we have to turn on TLSv1. - obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, minVersion: 'TLSv1', requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION }, onConnection) + obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, minVersion: 'TLSv1', requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA:@SECLEVEL=0", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION }, onConnection) } //obj.server.on('error', function () { console.log('MPS tls server error'); }); obj.server.on('newSession', function (id, data, cb) { if (tlsSessionStoreCount > 1000) { tlsSessionStoreCount = 0; tlsSessionStore = {}; } tlsSessionStore[id.toString('hex')] = data; tlsSessionStoreCount++; cb(); }); @@ -733,7 +733,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { return; } else { // Attempts reverse DNS loopup on the device IP address - require('dns').reverse(socket.remoteAddr, function (err, hostnames) { + const reverseDnsLookupHandler = function (err, hostnames) { var hostname = socket.remoteAddr; if ((err == null) && (hostnames != null) && (hostnames.length > 0)) { hostname = hostnames[0]; } @@ -752,7 +752,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { addedDeviceCount++; var change = 'Added CIRA device ' + socket.tag.name + ' to group ' + initialMesh.name; obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: initialMesh.domain }); - }); + } + try { require('dns').reverse(socket.remoteAddr, reverseDnsLookupHandler); } catch (ex) { reverseDnsLookupHandler(ex, null); } } } else { // Node is already present diff --git a/multiserver.js b/multiserver.js index 2a1aa9c6..7d87d09d 100644 --- a/multiserver.js +++ b/multiserver.js @@ -86,7 +86,7 @@ module.exports.CreateMultiServer = function (parent, args) { // Start authenticate the peer server by sending a auth nonce & server TLS cert hash. // Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce - obj.ws.send(obj.common.ShortToStr(1) + obj.serverCertHash + obj.nonce); // Command 1, hash + nonce + obj.ws.send(Buffer.from(obj.common.ShortToStr(1) + obj.serverCertHash + obj.nonce, 'binary')); // Command 1, hash + nonce }); // If a message is received @@ -101,7 +101,7 @@ module.exports.CreateMultiServer = function (parent, args) { switch (cmd) { case 1: { // Server authentication request - if (msg.length != 98) { obj.parent.parent.debug('peer', 'OutPeer: BAD MESSAGE(A1)'); return; } + if (msg.length != 98) { obj.parent.parent.debug('peer', 'OutPeer: Bad server authentication message, length = ' + msg.length + ', should be 98. HEX: ' + Buffer.from(msg.substring(0, 4096), 'binary').toString('hex')); return; } // Check that the server hash matches the TLS server certificate public key hash if (obj.url.toLowerCase().startsWith('wss://') && (obj.serverCertHash != msg.substring(2, 50))) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; } @@ -110,7 +110,7 @@ module.exports.CreateMultiServer = function (parent, args) { // Perform the hash signature using the server agent certificate obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, null, function (tag, signature) { // Send back our certificate + signature - if (obj.ws != null) { obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); } // Command 2, certificate + signature + if (obj.ws != null) { obj.ws.send(Buffer.from(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature, 'binary')); } // Command 2, certificate + signature }); break; @@ -139,7 +139,7 @@ module.exports.CreateMultiServer = function (parent, args) { // Send information about our server to the peer if (obj.connectionState == 15) { - obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); + obj.send({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }); for (var i in obj.pendingData) { processServerData(obj.pendingData[i]); } // Process any pending data obj.pendingData = []; } @@ -150,7 +150,7 @@ module.exports.CreateMultiServer = function (parent, args) { // Peer server confirmed authentication, we are allowed to send commands to the server obj.connectionState |= 8; if (obj.connectionState == 15) { - obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); + obj.send({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }); for (var i in obj.pendingData) { processServerData(obj.pendingData[i]); } // Process any pending data obj.pendingData = []; } @@ -187,9 +187,9 @@ module.exports.CreateMultiServer = function (parent, args) { obj.send = function (msg) { try { if (obj.ws == null || obj.connectionState != 15) { return; } - if (typeof msg == 'object') { obj.ws.send(JSON.stringify(msg)); return; } if (typeof msg == 'string') { obj.ws.send(msg); return; } - } catch (e) { } + if (typeof msg == 'object') { obj.ws.send(JSON.stringify(msg)); return; } + } catch (ex) { } }; // Process incoming peer server JSON data @@ -244,12 +244,11 @@ module.exports.CreateMultiServer = function (parent, args) { obj.parent.parent.debug('peer', 'InPeer: Connected (' + obj.remoteaddr + ')'); // Send a message to the peer server - obj.send = function (data) { + obj.send = function (msg) { try { - if (typeof data == 'string') { obj.ws.send(Buffer.from(data, 'binary')); return; } - if (typeof data == 'object') { obj.ws.send(JSON.stringify(data)); return; } - obj.ws.send(data); - } catch (e) { } + if (typeof msg == 'string') { obj.ws.send(msg); return; } + if (typeof msg == 'object') { obj.ws.send(JSON.stringify(msg)); return; } + } catch (ex) { } }; // Disconnect this server @@ -281,7 +280,7 @@ module.exports.CreateMultiServer = function (parent, args) { // Perform the hash signature using the server agent certificate obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, null, function (tag, signature) { // Send back our certificate + signature - obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); // Command 2, certificate + signature + obj.ws.send(Buffer.from(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature, 'binary')); // Command 2, certificate + signature }); // Check the peer server signature if we can @@ -326,13 +325,13 @@ module.exports.CreateMultiServer = function (parent, args) { // Start authenticate the peer server by sending a auth nonce & server TLS cert hash. // Send 384 bits SHA382 hash of TLS cert public key + 384 bits nonce obj.nonce = obj.crypto.randomBytes(48).toString('binary'); - obj.send(obj.common.ShortToStr(1) + obj.webCertificateHash + obj.nonce); // Command 1, hash + nonce + obj.ws.send(Buffer.from(obj.common.ShortToStr(1) + obj.webCertificateHash + obj.nonce, 'binary')); // Command 1, hash + nonce // Once we get all the information about an peer server, run this to hook everything up to the server function completePeerServerConnection() { if (obj.authenticated != 1) return; - obj.send(obj.common.ShortToStr(4)); - obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); + obj.ws.send(Buffer.from(obj.common.ShortToStr(4), 'binary')); + obj.send({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }); obj.authenticated = 2; // Process any pending data that was received before peer authentication @@ -405,8 +404,7 @@ module.exports.CreateMultiServer = function (parent, args) { // Dispatch an event to all other MeshCentral2 peer servers obj.DispatchEvent = function (ids, source, event) { - var busmsg = JSON.stringify({ action: 'bus', ids: ids, event: event }); - for (var serverid in obj.peerServers) { obj.peerServers[serverid].send(busmsg); } + for (var serverid in obj.peerServers) { obj.peerServers[serverid].send({ action: 'bus', ids: ids, event: event }); } }; // Dispatch a message to other MeshCentral2 peer servers @@ -437,10 +435,10 @@ module.exports.CreateMultiServer = function (parent, args) { obj.peerServers[peerServerId] = server; // Send the list of connections to the peer - server.send(JSON.stringify({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] })); + server.send({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] }); // Send a list of user sessions to the peer - server.send(JSON.stringify({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) })); + server.send({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) }); }; // We disconnected to a peer server, clean up everything @@ -588,6 +586,20 @@ module.exports.CreateMultiServer = function (parent, args) { } break; } + case 'agentCommand': { + if (msg.nodeid != null) { + // Route this message to a connected agent + var agent = obj.parent.webserver.wsagents[msg.nodeid]; + if (agent != null) { agent.send(JSON.stringify(msg.command)); } + } else if (msg.meshid != null) { + // Route this message to all connected agents of this mesh + for (var nodeid in obj.parent.webserver.wsagents) { + var agent = obj.parent.webserver.wsagents[nodeid]; + if (agent.dbMeshKey == msg.meshid) { try { agent.send(JSON.stringify(msg.command)); } catch (ex) { } } + } + } + break; + } default: { // Unknown peer server command console.log('Unknown action from peer server ' + peerServerId + ': ' + msg.action + '.'); @@ -636,7 +648,7 @@ module.exports.CreateMultiServer = function (parent, args) { peerTunnel.ws2.on('close', function (req) { peerTunnel.parent.parent.debug('peer', 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); }); // If a message is received from the peer, Peer ---> Browser (TODO: Pipe this?) - peerTunnel.ws2.on('message', function (msg) { try { peerTunnel.ws2._socket.pause(); peerTunnel.ws1.send(msg, function () { peerTunnel.ws2._socket.resume(); }); } catch (e) { } }); + peerTunnel.ws2.on('message', function (msg, isBinary) { try { peerTunnel.ws2._socket.pause(); peerTunnel.ws1.send((isBinary ? msg : msg.toString('binary')), function () { peerTunnel.ws2._socket.resume(); }); } catch (e) { } }); // Register the connection event peerTunnel.ws2.on('open', function () { diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..caf31a34 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2448 @@ +{ + "name": "meshcentral", + "version": "1.1.35", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "meshcentral", + "version": "1.1.35", + "license": "Apache-2.0", + "dependencies": { + "@seald-io/nedb": "4.0.4", + "archiver": "7.0.1", + "body-parser": "1.20.3", + "cbor": "5.2.0", + "compression": "1.7.5", + "cookie-session": "2.1.0", + "express": "4.21.2", + "express-handlebars": "7.1.3", + "express-ws": "5.0.2", + "ipcheck": "0.1.0", + "minimist": "1.2.8", + "multiparty": "4.2.3", + "node-forge": "1.3.1", + "ua-parser-js": "1.0.39", + "ws": "8.18.0", + "yauzl": "2.10.0" + }, + "bin": { + "meshcentral": "bin/meshcentral" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@seald-io/binary-search-tree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.3.tgz", + "integrity": "sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA==" + }, + "node_modules/@seald-io/nedb": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@seald-io/nedb/-/nedb-4.0.4.tgz", + "integrity": "sha512-CUNcMio7QUHTA+sIJ/DC5JzVNNsHe743TPmC4H5Gij9zDLMbmrCT2li3eVB72/gF63BPS8pWEZrjlAMRKA8FDw==", + "license": "MIT", + "dependencies": { + "@seald-io/binary-search-tree": "^1.0.3", + "localforage": "^1.9.0", + "util": "^0.12.4" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/archiver-utils/node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", + "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/archiver/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", + "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", + "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-session": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.1.0.tgz", + "integrity": "sha512-u73BDmR8QLGcs+Lprs0cfbcAPKl2HnPcjpwRXT41sEV4DRJ2+W0vJEEZkG31ofkx+HZflA70siRIjiTdIodmOQ==", + "license": "MIT", + "dependencies": { + "cookies": "0.9.1", + "debug": "3.2.7", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cookie-session/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/cookie-session/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookies": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz", + "integrity": "sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", + "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-handlebars": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-7.1.3.tgz", + "integrity": "sha512-O0W4n14iQ8+iFIDdiMh9HRI2nbVQJ/h1qndlD1TXWxxcfbKjKoqJh+ti2tROkyx4C4VQrt0y3bANBQ5auQAiew==", + "license": "BSD-3-Clause", + "dependencies": { + "glob": "^10.4.2", + "graceful-fs": "^4.2.11", + "handlebars": "^4.7.8" + }, + "engines": { + "node": ">=v16" + } + }, + "node_modules/express-ws": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz", + "integrity": "sha512-0uvmuk61O9HXgLhGl3QhNSEtRsQevtmbL94/eILaliEADZBHZOQUAiHFrGPrgsjikohyrmSG5g+sCfASTt0lkQ==", + "license": "BSD-2-Clause", + "dependencies": { + "ws": "^7.4.6" + }, + "engines": { + "node": ">=4.5.0" + }, + "peerDependencies": { + "express": "^4.0.0 || ^5.0.0-alpha.1" + } + }, + "node_modules/express-ws/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipcheck": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ipcheck/-/ipcheck-0.1.0.tgz", + "integrity": "sha512-NwhrmROU0iXKa+U1quGuQ+ag+K/1Bb5V/yh5Q4SylSu/LGymPZcWB7p4u7JgJH0qOR6cTLDO5VZlRbhoeekNzQ==", + "license": "MIT" + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jackspeak/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jackspeak/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jackspeak/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/jackspeak/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/jackspeak/node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "license": "MIT", + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "license": "Apache-2.0", + "dependencies": { + "lie": "3.1.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/multiparty": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz", + "integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==", + "license": "MIT", + "dependencies": { + "http-errors": "~1.8.1", + "safe-buffer": "5.2.1", + "uid-safe": "2.1.5" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/multiparty/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multiparty/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multiparty/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "license": "MIT" + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamx": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz", + "integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "license": "MIT", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.39.tgz", + "integrity": "sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yauzl/node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", + "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + } + } +} diff --git a/package.json b/package.json index eb8c9a19..78cd22bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "1.0.95", + "version": "1.1.42", "keywords": [ "Remote Device Management", "Remote Device Monitoring", @@ -37,24 +37,25 @@ "sample-config-advanced.json" ], "dependencies": { - "archiver": "^5.3.1", - "body-parser": "^1.19.0", - "cbor": "~5.2.0", - "compression": "^1.7.4", - "cookie-session": "^1.4.0", - "express": "^4.17.0", - "express-handlebars": "^5.3.5", - "express-ws": "^4.0.0", - "ipcheck": "^0.1.0", - "minimist": "^1.2.5", - "multiparty": "^4.2.1", - "@yetzt/nedb": "^1.8.0", - "node-forge": "^1.0.0", - "ws": "^5.2.3", - "yauzl": "^2.10.0" + "@seald-io/nedb": "4.0.4", + "archiver": "7.0.1", + "body-parser": "1.20.3", + "cbor": "5.2.0", + "compression": "1.7.5", + "cookie-session": "2.1.0", + "express": "4.21.2", + "express-handlebars": "7.1.3", + "express-ws": "5.0.2", + "ipcheck": "0.1.0", + "minimist": "1.2.8", + "multiparty": "4.2.3", + "node-forge": "1.3.1", + "ua-parser-js": "1.0.39", + "ws": "8.18.0", + "yauzl": "2.10.0" }, "engines": { - "node": ">=10.0.0" + "node": ">=16.0.0" }, "repository": { "type": "git", diff --git a/pluginHandler.js b/pluginHandler.js index 83138a4c..47c2a42d 100644 --- a/pluginHandler.js +++ b/pluginHandler.js @@ -139,7 +139,7 @@ module.exports.pluginHandler = function (parent) { try { obj.plugins[p][hookName](...args); } catch (e) { - console.log("Error ocurred while running plugin hook" + p + ':' + hookName + ' (' + e + ')'); + console.log("Error occurred while running plugin hook " + p + ':' + hookName, e); } } } @@ -205,7 +205,7 @@ module.exports.pluginHandler = function (parent) { panel[p].header = obj.plugins[p].on_device_header(); panel[p].content = obj.plugins[p].on_device_page(); } catch (e) { - console.log("Error ocurred while getting plugin views " + p + ':' + ' (' + e + ')'); + console.log("Error occurred while getting plugin views " + p + ':' + ' (' + e + ')'); } } } @@ -364,7 +364,7 @@ module.exports.pluginHandler = function (parent) { if (force_url != null) dl_url = force_url; var url = require('url'); var q = url.parse(dl_url, true); - var http = (q.protocol == "http") ? require('http') : require('https'); + var http = (q.protocol == "http:") ? require('http') : require('https'); var opts = { path: q.pathname, host: q.hostname, @@ -409,7 +409,13 @@ module.exports.pluginHandler = function (parent) { zipfile.openReadStream(entry, function (err, readStream) { if (err) throw err; readStream.on('end', function () { zipfile.readEntry(); }); - readStream.pipe(obj.fs.createWriteStream(filePath)); + if (process.platform == 'win32') { + readStream.pipe(obj.fs.createWriteStream(filePath)); + } else { + var fileMode = (entry.externalFileAttributes >> 16) & 0x0fff; + if( fileMode <= 0 ) fileMode = 0o644; + readStream.pipe(obj.fs.createWriteStream(filePath, { mode: fileMode })); + } }); } }); @@ -451,7 +457,7 @@ module.exports.pluginHandler = function (parent) { if (plugin.versionHistoryUrl == null) reject("No version history available for this plugin."); var url = require('url'); var q = url.parse(plugin.versionHistoryUrl, true); - var http = (q.protocol == 'http') ? require('http') : require('https'); + var http = (q.protocol == 'http:') ? require('http') : require('https'); var opts = { path: q.pathname, host: q.hostname, @@ -535,4 +541,4 @@ module.exports.pluginHandler = function (parent) { } } return obj; -}; \ No newline at end of file +}; diff --git a/plugin_development.md b/plugin_development.md deleted file mode 100644 index f93066fe..00000000 --- a/plugin_development.md +++ /dev/null @@ -1,92 +0,0 @@ -# Plugin Development - -## Overview - -## Anatomy of a plugin: - - - plugin_name/ - -- config.json - -- plugin_name.js - -- modules_meshcore/ // optional - --- plugin_name.js // optional - -## Plugin Configuration File -A valid JSON object within a file named `config.json` in the root folder of your project. An example: - - { - "name": "Plugin Name", - "shortName": "plugin_name", - "version": "0.0.0", - "author": "Author Name", - "description": "Short Description of the plugin", - "hasAdminPanel": false, - "homepage": "https://www.example.com", - "changelogUrl": "https://raw.githubusercontent.com/User/Project/master/changelog.md", - "configUrl": "https://raw.githubusercontent.com/User/Project/master/config.json", - "downloadUrl": "https://github.com/User/Project/archive/master.zip", - "repository": { - "type": "git", - "url": "https://github.com/User/Project.git" - }, - "versionHistoryUrl": "https://api.github.com/repos/User/Project/tags", - "meshCentralCompat": ">0.4.3" - } - -## Configuration File Properties -| Field | Required | Type | Description -|--|--|--|--| -| name | Yes | string | a human-readable name for the plugin -| shortName | Yes | string | an alphanumeric, unique short identifier for the plugin (will be used to access your functions throughout the project -| version | Yes | string | the current version of the plugin -| author | No | string | the author's name -| description | Yes | string | a short, human-readable description of what the plugin does -| hasAdminPanel | Yes | boolean | `true` or `false`, indicates whether or not the plugin will offer its own administrative interface -| homepage | Yes | string | the URL of the projects homepage -| changelogUrl | Yes | string | the URL to the changelog of the project -| configUrl | Yes | string | the URL to the config.json of the project -| downloadUrl | Yes | string | the URL to a ZIP of the project (used for installation/upgrades) -| repository | Yes | JSON object | contains the following attributes -| repository.type | Yes | string | valid values are `git` and in the future, `npm` will also be supported in the future -| repository.url | Yes | string | the URL to the project's repository -| versionHistoryUrl | No | string | the URL to the project's versions/tags -| meshCentralCompat | Yes | string | the minimum version string of required compatibility with the MeshCentral server, can be formatted as "0.1.2-c" or ">=0.1.2-c". Currently only supports minimum version, not full semantic checking. - -## Plugin Hooks -These are separated into the following categories depending on the type of functionality the plugin should offer. - -- Web UI, to modify the MeshCentral admin interface -- Back End, to modify core functionality of the server and communicate with the Web UI layer as well as the Mesh Agent (Node) layer to send commands and data -- Mesh Agent (Node), to introduce functionality to each agent - -### Web UI Hooks -`onDeviceRefreshEnd`: called when a device is selected in the MeshCentral web interface -`registerPluginTab`: callable when a device is selected in the MeshCentral web interface to register a new tab for plugin data, if required. Accepts an object, or function that returns an object, with the following properties: { tabId: "yourShortNameHere", tabTitle: "Your Display Name"}. A tab and div with the associated ID and title will be created for your use -`onDesktopDisconnect`: called when a remote desktop session is disconnected -`onWebUIStartupEnd`: called when the page has loaded for the first time after a login / refresh -`goPageStart`: called before page changes take effect. Passes 2 arguments ( : int, : Event) -`goPageEnd`: called after page changes take effect. Passes 2 arguments ( : int, : Event) - -#### Exports -Any function can be exported to the Web UI layer by adding the name of the function to an `exports` array in the plugin object. - -### Back End Hooks -`server_startup`: called once when the server starts (or when the plugin is first installed) -`hook_agentCoreIsStable`: called once when an agent initially checks in -`hook_processAgentData`: called each time an agent transmits data back to the server -`hook_userLoggedIn`: called when a user has logged into the web interface - -### Mesh Agent -Use of the optional file `plugin_name.js` in the optional folder `modules_meshcore` will include the file in the default meshcore file sent to each endpoint. This is useful to add functionality on each of the endpoints. - -## Structure -Much of MeshCentral revolves around returning objects for your structures, and plugins are no different. Within your plugin you can traverse all the way up to the web server and MeshCentral Server classes to access all the functionality those layers provide. This is done by passing the current object to newly created objects, and assigning that reference to a `parent` variable within that object. - - -## Versioning -Versioning your plugin correctly and consistently is essential to ensure users of your plugin are prompted to upgrade when it is available. Semantic versioning is recommended. - -## Changelog -A changelog is highly recommended so that your users know what's changed since their last version. - -## Sample Plugin -[MeshCentral-Sample](https://github.com/ryanblenis/MeshCentral-Sample) is a simple plugin that, upon disconnecting from remote desktop, prompts the user to enter a manual event (note), pre-filled in with the date and timestamp. diff --git a/public/images/amazon-appstore-140.png b/public/images/amazon-appstore-140.png new file mode 100644 index 00000000..7a6625e0 Binary files /dev/null and b/public/images/amazon-appstore-140.png differ diff --git a/public/images/amazon-appstore-280.png b/public/images/amazon-appstore-280.png new file mode 100644 index 00000000..6df0b435 Binary files /dev/null and b/public/images/amazon-appstore-280.png differ diff --git a/public/images/details/tpm32.png b/public/images/details/tpm32.png new file mode 100644 index 00000000..aeefe003 Binary files /dev/null and b/public/images/details/tpm32.png differ diff --git a/public/images/details/tpm64.png b/public/images/details/tpm64.png new file mode 100644 index 00000000..741cab15 Binary files /dev/null and b/public/images/details/tpm64.png differ diff --git a/public/images/duo-2fa-250-disable.png b/public/images/duo-2fa-250-disable.png new file mode 100644 index 00000000..01d91b18 Binary files /dev/null and b/public/images/duo-2fa-250-disable.png differ diff --git a/public/images/duo-2fa-250.png b/public/images/duo-2fa-250.png new file mode 100644 index 00000000..00941405 Binary files /dev/null and b/public/images/duo-2fa-250.png differ diff --git a/public/images/google-play-140.png b/public/images/google-play-140.png new file mode 100644 index 00000000..b5b1a730 Binary files /dev/null and b/public/images/google-play-140.png differ diff --git a/public/images/google-play-280.png b/public/images/google-play-280.png new file mode 100644 index 00000000..25237068 Binary files /dev/null and b/public/images/google-play-280.png differ diff --git a/public/images/icon-background-red.png b/public/images/icon-background-red.png new file mode 100644 index 00000000..18337406 Binary files /dev/null and b/public/images/icon-background-red.png differ diff --git a/public/images/key16.png b/public/images/key16.png new file mode 100644 index 00000000..a184527f Binary files /dev/null and b/public/images/key16.png differ diff --git a/public/images/login/2fa-duo-48.png b/public/images/login/2fa-duo-48.png new file mode 100644 index 00000000..0c5d0afd Binary files /dev/null and b/public/images/login/2fa-duo-48.png differ diff --git a/public/images/login/2fa-duo-96.png b/public/images/login/2fa-duo-96.png new file mode 100644 index 00000000..5586963d Binary files /dev/null and b/public/images/login/2fa-duo-96.png differ diff --git a/public/images/MeshIcon100.png b/public/images/meshicon100.png similarity index 100% rename from public/images/MeshIcon100.png rename to public/images/meshicon100.png diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index 145bfc45..00000000 --- a/public/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "MeshCentral", - "short_name": "MeshCentral", - "description": "Open source web based, remote computer management.", - "scope": ".", - "start_url": "/", - "display": "fullscreen", - "orientation": "portrait", - "theme_color": "#ffffff", - "background_color": "#ffffff", - "icons": [ - { - "src": "android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} \ No newline at end of file diff --git a/public/mstsc/client.js b/public/mstsc/client.js index 317a5114..bc26d72b 100644 --- a/public/mstsc/client.js +++ b/public/mstsc/client.js @@ -16,6 +16,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +/* + * added get clipboard from remote RDP - Simon Smith 2024 + * added set clipboard to remote RDP - Simon Smith 2024 + */ (function() { /** @@ -173,6 +177,20 @@ options: options, locale: Mstsc.locale() }])); + self.prevClipboardText = null; + self.clipboardReadTimer = setInterval(function(){ + if(navigator.clipboard.readText != null){ + if (Mstsc.browser() == 'firefox') return; // this is needed because firefox pops up a PASTE option every second which is annoying + navigator.clipboard.readText() + .then(function(data){ + if(data != self.prevClipboard){ + self.prevClipboard = data; + if (self.socket) { self.socket.send(JSON.stringify(['clipboard', data])); } + } + }) + .catch(function(){ }); + } + }, 1000); }; this.socket.onmessage = function (evt) { if (typeof evt.data == 'string') { @@ -206,6 +224,14 @@ next(err); break; } + case 'rdp-clipboard': { + if ((msg[1] != null) && (navigator.clipboard.writeText != null)) { + navigator.clipboard.writeText(msg[1]) // Put remote clipboard data into our clipboard + .then(function() { }) + .catch(function(err) { console.log('clipboard.writeText Error', err); }); + } + break; + } } } else { // This is binary bitmap data, store it. @@ -215,6 +241,8 @@ this.socket.onclose = function () { //console.log("WS-CLOSE"); self.activeSession = false; + clearInterval(self.clipboardReadTimer); + self.prevClipboardText = null; next(null); }; } diff --git a/public/novnc/LICENSE.txt b/public/novnc/LICENSE.txt index ee81d202..37efdcdb 100644 --- a/public/novnc/LICENSE.txt +++ b/public/novnc/LICENSE.txt @@ -1,4 +1,4 @@ -noVNC is Copyright (C) 2019 The noVNC Authors +noVNC is Copyright (C) 2022 The noVNC Authors (./AUTHORS) The noVNC core library files are licensed under the MPL 2.0 (Mozilla diff --git a/public/novnc/app/error-handler.js b/public/novnc/app/error-handler.js index 81a6cba8..67b63720 100644 --- a/public/novnc/app/error-handler.js +++ b/public/novnc/app/error-handler.js @@ -6,61 +6,74 @@ * See README.md for usage and integration instructions. */ -// NB: this should *not* be included as a module until we have -// native support in the browsers, so that our error handler -// can catch script-loading errors. +// Fallback for all uncought errors +function handleError(event, err) { + try { + const msg = document.getElementById('noVNC_fallback_errormsg'); -// No ES6 can be used in this file since it's used for the translation -/* eslint-disable prefer-arrow-callback */ - -(function _scope() { - "use strict"; - - // Fallback for all uncought errors - function handleError(event, err) { - try { - const msg = document.getElementById('noVNC_fallback_errormsg'); - - // Only show the initial error - if (msg.hasChildNodes()) { - return false; - } - - let div = document.createElement("div"); - div.classList.add('noVNC_message'); - div.appendChild(document.createTextNode(event.message)); - msg.appendChild(div); - - if (event.filename) { - div = document.createElement("div"); - div.className = 'noVNC_location'; - let text = event.filename; - if (event.lineno !== undefined) { - text += ":" + event.lineno; - if (event.colno !== undefined) { - text += ":" + event.colno; - } - } - div.appendChild(document.createTextNode(text)); - msg.appendChild(div); - } - - if (err && err.stack) { - div = document.createElement("div"); - div.className = 'noVNC_stack'; - div.appendChild(document.createTextNode(err.stack)); - msg.appendChild(div); - } - - document.getElementById('noVNC_fallback_error') - .classList.add("noVNC_open"); - } catch (exc) { - document.write("noVNC encountered an error."); + // Work around Firefox bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1685038 + if (event.message === "ResizeObserver loop completed with undelivered notifications.") { + return false; } - // Don't return true since this would prevent the error - // from being printed to the browser console. - return false; + + // Only show the initial error + if (msg.hasChildNodes()) { + return false; + } + + let div = document.createElement("div"); + div.classList.add('noVNC_message'); + div.appendChild(document.createTextNode(event.message)); + msg.appendChild(div); + + if (event.filename) { + div = document.createElement("div"); + div.className = 'noVNC_location'; + let text = event.filename; + if (event.lineno !== undefined) { + text += ":" + event.lineno; + if (event.colno !== undefined) { + text += ":" + event.colno; + } + } + div.appendChild(document.createTextNode(text)); + msg.appendChild(div); + } + + if (err && err.stack) { + div = document.createElement("div"); + div.className = 'noVNC_stack'; + div.appendChild(document.createTextNode(err.stack)); + msg.appendChild(div); + } + + document.getElementById('noVNC_fallback_error') + .classList.add("noVNC_open"); + + } catch (exc) { + document.write("noVNC encountered an error."); } - window.addEventListener('error', function onerror(evt) { handleError(evt, evt.error); }); - window.addEventListener('unhandledrejection', function onreject(evt) { handleError(evt.reason, evt.reason); }); -})(); + + // Try to disable keyboard interaction, best effort + try { + // Remove focus from the currently focused element in order to + // prevent keyboard interaction from continuing + if (document.activeElement) { document.activeElement.blur(); } + + // Don't let any element be focusable when showing the error + let keyboardFocusable = 'a[href], button, input, textarea, select, details, [tabindex]'; + document.querySelectorAll(keyboardFocusable).forEach((elem) => { + elem.setAttribute("tabindex", "-1"); + }); + } catch (exc) { + // Do nothing + } + + // Don't return true since this would prevent the error + // from being printed to the browser console. + return false; +} + +window.addEventListener('error', evt => handleError(evt, evt.error)); +window.addEventListener('unhandledrejection', evt => handleError(evt.reason, evt.reason)); diff --git a/public/novnc/app/images/icons/Makefile b/public/novnc/app/images/icons/Makefile index be564b43..03eaed07 100644 --- a/public/novnc/app/images/icons/Makefile +++ b/public/novnc/app/images/icons/Makefile @@ -1,42 +1,42 @@ -ICONS := \ - novnc-16x16.png \ - novnc-24x24.png \ - novnc-32x32.png \ - novnc-48x48.png \ - novnc-64x64.png +BROWSER_SIZES := 16 24 32 48 64 +#ANDROID_SIZES := 72 96 144 192 +# FIXME: The ICO is limited to 8 icons due to a Chrome bug: +# https://bugs.chromium.org/p/chromium/issues/detail?id=1381393 +ANDROID_SIZES := 96 144 192 +WEB_ICON_SIZES := $(BROWSER_SIZES) $(ANDROID_SIZES) -ANDROID_LAUNCHER := \ - novnc-48x48.png \ - novnc-72x72.png \ - novnc-96x96.png \ - novnc-144x144.png \ - novnc-192x192.png +#IOS_1X_SIZES := 20 29 40 76 # No such devices exist anymore +IOS_2X_SIZES := 40 58 80 120 152 167 +IOS_3X_SIZES := 60 87 120 180 +ALL_IOS_SIZES := $(IOS_1X_SIZES) $(IOS_2X_SIZES) $(IOS_3X_SIZES) -IPHONE_LAUNCHER := \ - novnc-60x60.png \ - novnc-120x120.png - -IPAD_LAUNCHER := \ - novnc-76x76.png \ - novnc-152x152.png - -ALL_ICONS := $(ICONS) $(ANDROID_LAUNCHER) $(IPHONE_LAUNCHER) $(IPAD_LAUNCHER) +ALL_ICONS := \ + $(ALL_IOS_SIZES:%=novnc-ios-%.png) \ + novnc.ico all: $(ALL_ICONS) -novnc-16x16.png: novnc-icon-sm.svg - convert -density 90 \ - -background transparent "$<" "$@" -novnc-24x24.png: novnc-icon-sm.svg - convert -density 135 \ - -background transparent "$<" "$@" -novnc-32x32.png: novnc-icon-sm.svg - convert -density 180 \ - -background transparent "$<" "$@" +# Our testing shows that the ICO file need to be sorted in largest to +# smallest to get the apporpriate behviour +WEB_ICON_SIZES_REVERSE := $(shell echo $(WEB_ICON_SIZES) | tr ' ' '\n' | sort -nr | tr '\n' ' ') +WEB_BASE_ICONS := $(WEB_ICON_SIZES_REVERSE:%=novnc-%.png) +.INTERMEDIATE: $(WEB_BASE_ICONS) +novnc.ico: $(WEB_BASE_ICONS) + convert $(WEB_BASE_ICONS) "$@" + +# General conversion novnc-%.png: novnc-icon.svg - convert -density $$[`echo $* | cut -d x -f 1` * 90 / 48] \ - -background transparent "$<" "$@" + convert -depth 8 -background transparent \ + -size $*x$* "$(lastword $^)" "$@" + +# iOS icons use their own SVG +novnc-ios-%.png: novnc-ios-icon.svg + convert -depth 8 -background transparent \ + -size $*x$* "$(lastword $^)" "$@" + +# The smallest sizes are generated using a different SVG +novnc-16.png novnc-24.png novnc-32.png: novnc-icon-sm.svg clean: rm -f *.png diff --git a/public/novnc/app/images/icons/novnc-120x120.png b/public/novnc/app/images/icons/novnc-120x120.png deleted file mode 100644 index 40823efb..00000000 Binary files a/public/novnc/app/images/icons/novnc-120x120.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-144x144.png b/public/novnc/app/images/icons/novnc-144x144.png deleted file mode 100644 index eee71f11..00000000 Binary files a/public/novnc/app/images/icons/novnc-144x144.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-152x152.png b/public/novnc/app/images/icons/novnc-152x152.png deleted file mode 100644 index 0694b2de..00000000 Binary files a/public/novnc/app/images/icons/novnc-152x152.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-16x16.png b/public/novnc/app/images/icons/novnc-16x16.png deleted file mode 100644 index 42108f40..00000000 Binary files a/public/novnc/app/images/icons/novnc-16x16.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-192x192.png b/public/novnc/app/images/icons/novnc-192x192.png deleted file mode 100644 index ef9201f4..00000000 Binary files a/public/novnc/app/images/icons/novnc-192x192.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-24x24.png b/public/novnc/app/images/icons/novnc-24x24.png deleted file mode 100644 index 11061359..00000000 Binary files a/public/novnc/app/images/icons/novnc-24x24.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-32x32.png b/public/novnc/app/images/icons/novnc-32x32.png deleted file mode 100644 index ff00dc30..00000000 Binary files a/public/novnc/app/images/icons/novnc-32x32.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-48x48.png b/public/novnc/app/images/icons/novnc-48x48.png deleted file mode 100644 index f24cd6cc..00000000 Binary files a/public/novnc/app/images/icons/novnc-48x48.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-60x60.png b/public/novnc/app/images/icons/novnc-60x60.png deleted file mode 100644 index 06b0d609..00000000 Binary files a/public/novnc/app/images/icons/novnc-60x60.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-64x64.png b/public/novnc/app/images/icons/novnc-64x64.png deleted file mode 100644 index 6d0fb341..00000000 Binary files a/public/novnc/app/images/icons/novnc-64x64.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-72x72.png b/public/novnc/app/images/icons/novnc-72x72.png deleted file mode 100644 index 23163a22..00000000 Binary files a/public/novnc/app/images/icons/novnc-72x72.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-76x76.png b/public/novnc/app/images/icons/novnc-76x76.png deleted file mode 100644 index aef61c48..00000000 Binary files a/public/novnc/app/images/icons/novnc-76x76.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-96x96.png b/public/novnc/app/images/icons/novnc-96x96.png deleted file mode 100644 index 1a77c53f..00000000 Binary files a/public/novnc/app/images/icons/novnc-96x96.png and /dev/null differ diff --git a/public/novnc/app/images/icons/novnc-ios-120.png b/public/novnc/app/images/icons/novnc-ios-120.png new file mode 100644 index 00000000..8da7bab3 Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-120.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-152.png b/public/novnc/app/images/icons/novnc-ios-152.png new file mode 100644 index 00000000..60b2bcef Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-152.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-167.png b/public/novnc/app/images/icons/novnc-ios-167.png new file mode 100644 index 00000000..98fade2e Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-167.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-180.png b/public/novnc/app/images/icons/novnc-ios-180.png new file mode 100644 index 00000000..5d24df70 Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-180.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-40.png b/public/novnc/app/images/icons/novnc-ios-40.png new file mode 100644 index 00000000..cf14894d Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-40.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-58.png b/public/novnc/app/images/icons/novnc-ios-58.png new file mode 100644 index 00000000..f6dfbebd Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-58.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-60.png b/public/novnc/app/images/icons/novnc-ios-60.png new file mode 100644 index 00000000..8cda2953 Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-60.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-80.png b/public/novnc/app/images/icons/novnc-ios-80.png new file mode 100644 index 00000000..6c417c47 Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-80.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-87.png b/public/novnc/app/images/icons/novnc-ios-87.png new file mode 100644 index 00000000..4377d874 Binary files /dev/null and b/public/novnc/app/images/icons/novnc-ios-87.png differ diff --git a/public/novnc/app/images/icons/novnc-ios-icon.svg b/public/novnc/app/images/icons/novnc-ios-icon.svg new file mode 100644 index 00000000..009452ac --- /dev/null +++ b/public/novnc/app/images/icons/novnc-ios-icon.svg @@ -0,0 +1,183 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/novnc/app/images/icons/novnc.ico b/public/novnc/app/images/icons/novnc.ico new file mode 100644 index 00000000..c3bc58e3 Binary files /dev/null and b/public/novnc/app/images/icons/novnc.ico differ diff --git a/public/novnc/app/locale/el.json b/public/novnc/app/locale/el.json index f801251c..4df3e03c 100644 --- a/public/novnc/app/locale/el.json +++ b/public/novnc/app/locale/el.json @@ -1,4 +1,5 @@ { + "HTTPS is required for full functionality": "Το HTTPS είναι απαιτούμενο για πλήρη λειτουργικότητα", "Connecting...": "Συνδέεται...", "Disconnecting...": "Aποσυνδέεται...", "Reconnecting...": "Επανασυνδέεται...", @@ -7,19 +8,15 @@ "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ", "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ", "Something went wrong, connection is closed": "Κάτι πήγε στραβά, η σύνδεση διακόπηκε", + "Failed to connect to server": "Αποτυχία στη σύνδεση με το διακομιστή", "Disconnected": "Αποσυνδέθηκε", "New connection has been rejected with reason: ": "Η νέα σύνδεση απορρίφθηκε διότι: ", "New connection has been rejected": "Η νέα σύνδεση απορρίφθηκε ", - "Password is required": "Απαιτείται ο κωδικός πρόσβασης", + "Credentials are required": "Απαιτούνται διαπιστευτήρια", "noVNC encountered an error:": "το noVNC αντιμετώπισε ένα σφάλμα:", "Hide/Show the control bar": "Απόκρυψη/Εμφάνιση γραμμής ελέγχου", + "Drag": "Σύρσιμο", "Move/Drag Viewport": "Μετακίνηση/Σύρσιμο Θεατού πεδίου", - "viewport drag": "σύρσιμο θεατού πεδίου", - "Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού", - "No mousebutton": "Χωρίς Πλήκτρο Ποντικιού", - "Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού", - "Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού", - "Right mousebutton": "Δεξί Πλήκτρο Ποντικιού", "Keyboard": "Πληκτρολόγιο", "Show Keyboard": "Εμφάνιση Πληκτρολογίου", "Extra keys": "Επιπλέον πλήκτρα", @@ -28,6 +25,8 @@ "Toggle Ctrl": "Εναλλαγή Ctrl", "Alt": "Alt", "Toggle Alt": "Εναλλαγή Alt", + "Toggle Windows": "Εναλλαγή Παράθυρων", + "Windows": "Παράθυρα", "Send Tab": "Αποστολή Tab", "Tab": "Tab", "Esc": "Esc", @@ -41,8 +40,7 @@ "Reboot": "Επανεκκίνηση", "Reset": "Επαναφορά", "Clipboard": "Πρόχειρο", - "Clear": "Καθάρισμα", - "Fullscreen": "Πλήρης Οθόνη", + "Edit clipboard content in the textarea below.": "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω.", "Settings": "Ρυθμίσεις", "Shared Mode": "Κοινόχρηστη Λειτουργία", "View Only": "Μόνο Θέαση", @@ -52,6 +50,8 @@ "Local Scaling": "Τοπική Κλιμάκωση", "Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους", "Advanced": "Για προχωρημένους", + "Quality:": "Ποιότητα:", + "Compression level:": "Επίπεδο συμπίεσης:", "Repeater ID:": "Repeater ID:", "WebSocket": "WebSocket", "Encrypt": "Κρυπτογράφηση", @@ -60,10 +60,20 @@ "Path:": "Διαδρομή:", "Automatic Reconnect": "Αυτόματη επανασύνδεση", "Reconnect Delay (ms):": "Καθυστέρηση επανασύνδεσης (ms):", + "Show Dot when No Cursor": "Εμφάνιση Τελείας όταν δεν υπάρχει Δρομέας", "Logging:": "Καταγραφή:", + "Version:": "Έκδοση:", "Disconnect": "Αποσύνδεση", "Connect": "Σύνδεση", + "Server identity": "Ταυτότητα Διακομιστή", + "The server has provided the following identifying information:": "Ο διακομιστής παρείχε την ακόλουθη πληροφορία ταυτοποίησης:", + "Fingerprint:": "Δακτυλικό αποτύπωμα:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Παρακαλώ επαληθεύσετε ότι η πληροφορία είναι σωστή και πιέστε \"Αποδοχή\". Αλλιώς πιέστε \"Απόρριψη\".", + "Approve": "Αποδοχή", + "Reject": "Απόρριψη", + "Credentials": "Διαπιστευτήρια", + "Username:": "Κωδικός Χρήστη:", "Password:": "Κωδικός Πρόσβασης:", - "Cancel": "Ακύρωση", - "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas" + "Send Credentials": "Αποστολή Διαπιστευτηρίων", + "Cancel": "Ακύρωση" } \ No newline at end of file diff --git a/public/novnc/app/locale/fr.json b/public/novnc/app/locale/fr.json index 19e8255b..c0eeec7d 100644 --- a/public/novnc/app/locale/fr.json +++ b/public/novnc/app/locale/fr.json @@ -4,18 +4,18 @@ "Reconnecting...": "Reconnexion en cours...", "Internal error": "Erreur interne", "Must set host": "Doit définir l'hôte", - "Connected (encrypted) to ": "Connecté (crypté) à ", - "Connected (unencrypted) to ": "Connecté (non crypté) à ", - "Something went wrong, connection is closed": "Quelque chose est arrivé, la connexion est fermée", + "Connected (encrypted) to ": "Connecté (chiffré) à ", + "Connected (unencrypted) to ": "Connecté (non chiffré) à ", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion a été fermée", "Failed to connect to server": "Échec de connexion au serveur", "Disconnected": "Déconnecté", - "New connection has been rejected with reason: ": "Une nouvelle connexion a été rejetée avec raison: ", + "New connection has been rejected with reason: ": "Une nouvelle connexion a été rejetée avec motif : ", "New connection has been rejected": "Une nouvelle connexion a été rejetée", "Credentials are required": "Les identifiants sont requis", - "noVNC encountered an error:": "noVNC a rencontré une erreur:", + "noVNC encountered an error:": "noVNC a rencontré une erreur :", "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", "Drag": "Faire glisser", - "Move/Drag Viewport": "Déplacer/faire glisser Viewport", + "Move/Drag Viewport": "Déplacer/faire glisser le Viewport", "Keyboard": "Clavier", "Show Keyboard": "Afficher le clavier", "Extra keys": "Touches supplémentaires", @@ -45,28 +45,28 @@ "Shared Mode": "Mode partagé", "View Only": "Afficher uniquement", "Clip to Window": "Clip à fenêtre", - "Scaling Mode:": "Mode mise à l'échelle:", + "Scaling Mode:": "Mode mise à l'échelle :", "None": "Aucun", "Local Scaling": "Mise à l'échelle locale", "Remote Resizing": "Redimensionnement à distance", "Advanced": "Avancé", - "Quality:": "Qualité:", - "Compression level:": "Niveau de compression:", - "Repeater ID:": "ID Répéteur:", + "Quality:": "Qualité :", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "ID Répéteur :", "WebSocket": "WebSocket", - "Encrypt": "Crypter", - "Host:": "Hôte:", - "Port:": "Port:", - "Path:": "Chemin:", + "Encrypt": "Chiffrer", + "Host:": "Hôte :", + "Port:": "Port :", + "Path:": "Chemin :", "Automatic Reconnect": "Reconnecter automatiquemen", - "Reconnect Delay (ms):": "Délai de reconnexion (ms):", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", - "Logging:": "Se connecter:", - "Version:": "Version:", + "Logging:": "Se connecter :", + "Version:": "Version :", "Disconnect": "Déconnecter", "Connect": "Connecter", - "Username:": "Nom d'utilisateur:", - "Password:": "Mot de passe:", + "Username:": "Nom d'utilisateur :", + "Password:": "Mot de passe :", "Send Credentials": "Envoyer les identifiants", "Cancel": "Annuler" } \ No newline at end of file diff --git a/public/novnc/app/locale/it.json b/public/novnc/app/locale/it.json new file mode 100644 index 00000000..18a7f744 --- /dev/null +++ b/public/novnc/app/locale/it.json @@ -0,0 +1,68 @@ +{ + "Connecting...": "Connessione in corso...", + "Disconnecting...": "Disconnessione...", + "Reconnecting...": "Riconnessione...", + "Internal error": "Errore interno", + "Must set host": "Devi impostare l'host", + "Connected (encrypted) to ": "Connesso (crittografato) a ", + "Connected (unencrypted) to ": "Connesso (non crittografato) a", + "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è stata chiusa", + "Failed to connect to server": "Impossibile connettersi al server", + "Disconnected": "Disconnesso", + "New connection has been rejected with reason: ": "La nuova connessione è stata rifiutata con motivo: ", + "New connection has been rejected": "La nuova connessione è stata rifiutata", + "Credentials are required": "Le credenziali sono obbligatorie", + "noVNC encountered an error:": "noVNC ha riscontrato un errore:", + "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", + "Keyboard": "Tastiera", + "Show Keyboard": "Mostra tastiera", + "Extra keys": "Tasti Aggiuntivi", + "Show Extra Keys": "Mostra Tasti Aggiuntivi", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Tieni premuto Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tieni premuto Alt", + "Toggle Windows": "Tieni premuto Windows", + "Windows": "Windows", + "Send Tab": "Invia Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Invia Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Canc", + "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", + "Shutdown/Reboot": "Spegnimento/Riavvio", + "Shutdown/Reboot...": "Spegnimento/Riavvio...", + "Power": "Alimentazione", + "Shutdown": "Spegnimento", + "Reboot": "Riavvio", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Pulisci", + "Fullscreen": "Schermo intero", + "Settings": "Impostazioni", + "Shared Mode": "Modalità condivisa", + "View Only": "Sola Visualizzazione", + "Scaling Mode:": "Modalità di ridimensionamento:", + "None": "Nessuna", + "Local Scaling": "Ridimensionamento Locale", + "Remote Resizing": "Ridimensionamento Remoto", + "Advanced": "Avanzate", + "Quality:": "Qualità:", + "Compression level:": "Livello Compressione:", + "Repeater ID:": "ID Ripetitore:", + "WebSocket": "WebSocket", + "Encrypt": "Crittografa", + "Host:": "Host:", + "Port:": "Porta:", + "Path:": "Percorso:", + "Automatic Reconnect": "Riconnessione Automatica", + "Reconnect Delay (ms):": "Ritardo Riconnessione (ms):", + "Show Dot when No Cursor": "Mostra Punto quando Nessun Cursore", + "Version:": "Versione:", + "Disconnect": "Disconnetti", + "Connect": "Connetti", + "Username:": "Utente:", + "Password:": "Password:", + "Send Credentials": "Invia Credenziale", + "Cancel": "Annulla" +} \ No newline at end of file diff --git a/public/novnc/app/locale/ja.json b/public/novnc/app/locale/ja.json index 43fc5bf3..70fd7a5d 100644 --- a/public/novnc/app/locale/ja.json +++ b/public/novnc/app/locale/ja.json @@ -1,4 +1,5 @@ { + "HTTPS is required for full functionality": "すべての機能を使用するにはHTTPS接続が必要です", "Connecting...": "接続しています...", "Disconnecting...": "切断しています...", "Reconnecting...": "再接続しています...", @@ -21,10 +22,10 @@ "Extra keys": "追加キー", "Show Extra Keys": "追加キーを表示", "Ctrl": "Ctrl", - "Toggle Ctrl": "Ctrl キーを切り替え", + "Toggle Ctrl": "Ctrl キーをトグル", "Alt": "Alt", - "Toggle Alt": "Alt キーを切り替え", - "Toggle Windows": "Windows キーを切り替え", + "Toggle Alt": "Alt キーをトグル", + "Toggle Windows": "Windows キーをトグル", "Windows": "Windows", "Send Tab": "Tab キーを送信", "Tab": "Tab", @@ -39,11 +40,11 @@ "Reboot": "再起動", "Reset": "リセット", "Clipboard": "クリップボード", - "Clear": "クリア", - "Fullscreen": "全画面表示", + "Edit clipboard content in the textarea below.": "以下の入力欄からクリップボードの内容を編集できます。", + "Full Screen": "全画面表示", "Settings": "設定", "Shared Mode": "共有モード", - "View Only": "表示のみ", + "View Only": "表示専用", "Clip to Window": "ウィンドウにクリップ", "Scaling Mode:": "スケーリングモード:", "None": "なし", @@ -60,11 +61,18 @@ "Path:": "パス:", "Automatic Reconnect": "自動再接続", "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", - "Show Dot when No Cursor": "カーソルがないときにドットを表示", + "Show Dot when No Cursor": "カーソルがないときにドットを表示する", "Logging:": "ロギング:", "Version:": "バージョン:", "Disconnect": "切断", "Connect": "接続", + "Server identity": "サーバーの識別情報", + "The server has provided the following identifying information:": "サーバーは以下の識別情報を提供しています:", + "Fingerprint:": "フィンガープリント:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "この情報が正しい場合は「承認」を、そうでない場合は「拒否」を押してください。", + "Approve": "承認", + "Reject": "拒否", + "Credentials": "資格情報", "Username:": "ユーザー名:", "Password:": "パスワード:", "Send Credentials": "資格情報を送信", diff --git a/public/novnc/app/locale/sv.json b/public/novnc/app/locale/sv.json index e46df45b..80a400bf 100644 --- a/public/novnc/app/locale/sv.json +++ b/public/novnc/app/locale/sv.json @@ -1,9 +1,11 @@ { + "Running without HTTPS is not recommended, crashes or other issues are likely.": "Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är troliga.", "Connecting...": "Ansluter...", "Disconnecting...": "Kopplar ner...", "Reconnecting...": "Återansluter...", "Internal error": "Internt fel", "Must set host": "Du måste specifiera en värd", + "Failed to connect to server: ": "Misslyckades att ansluta till servern: ", "Connected (encrypted) to ": "Ansluten (krypterat) till ", "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", @@ -39,8 +41,8 @@ "Reboot": "Boota om", "Reset": "Återställ", "Clipboard": "Urklipp", - "Clear": "Rensa", - "Fullscreen": "Fullskärm", + "Edit clipboard content in the textarea below.": "Redigera urklippets innehåll i fältet nedan.", + "Full Screen": "Fullskärm", "Settings": "Inställningar", "Shared Mode": "Delat Läge", "View Only": "Endast Visning", @@ -65,6 +67,13 @@ "Version:": "Version:", "Disconnect": "Koppla från", "Connect": "Anslut", + "Server identity": "Server-identitet", + "The server has provided the following identifying information:": "Servern har gett följande identifierande information:", + "Fingerprint:": "Fingeravtryck:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck annars \"Neka\".", + "Approve": "Godkänn", + "Reject": "Neka", + "Credentials": "Användaruppgifter", "Username:": "Användarnamn:", "Password:": "Lösenord:", "Send Credentials": "Skicka Användaruppgifter", diff --git a/public/novnc/app/locale/zh_CN.json b/public/novnc/app/locale/zh_CN.json index f0aea9af..3679eadd 100644 --- a/public/novnc/app/locale/zh_CN.json +++ b/public/novnc/app/locale/zh_CN.json @@ -1,69 +1,69 @@ { "Connecting...": "连接中...", + "Connected (encrypted) to ": "已连接(已加密)到", + "Connected (unencrypted) to ": "已连接(未加密)到", "Disconnecting...": "正在断开连接...", - "Reconnecting...": "重新连接中...", - "Internal error": "内部错误", - "Must set host": "请提供主机名", - "Connected (encrypted) to ": "已连接到(加密)", - "Connected (unencrypted) to ": "已连接到(未加密)", - "Something went wrong, connection is closed": "发生错误,连接已关闭", - "Failed to connect to server": "无法连接到服务器", "Disconnected": "已断开连接", - "New connection has been rejected with reason: ": "连接被拒绝,原因:", - "New connection has been rejected": "连接被拒绝", + "Must set host": "必须设置主机", + "Reconnecting...": "重新连接中...", "Password is required": "请提供密码", + "Disconnect timeout": "超时断开", "noVNC encountered an error:": "noVNC 遇到一个错误:", "Hide/Show the control bar": "显示/隐藏控制栏", - "Move/Drag Viewport": "拖放显示范围", - "viewport drag": "显示范围拖放", - "Active Mouse Button": "启动鼠标按鍵", - "No mousebutton": "禁用鼠标按鍵", - "Left mousebutton": "鼠标左鍵", - "Middle mousebutton": "鼠标中鍵", - "Right mousebutton": "鼠标右鍵", + "Move/Drag Viewport": "移动/拖动窗口", + "viewport drag": "窗口拖动", + "Active Mouse Button": "启动鼠标按键", + "No mousebutton": "禁用鼠标按键", + "Left mousebutton": "鼠标左键", + "Middle mousebutton": "鼠标中键", + "Right mousebutton": "鼠标右键", "Keyboard": "键盘", "Show Keyboard": "显示键盘", "Extra keys": "额外按键", "Show Extra Keys": "显示额外按键", "Ctrl": "Ctrl", "Toggle Ctrl": "切换 Ctrl", + "Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。", "Alt": "Alt", "Toggle Alt": "切换 Alt", "Send Tab": "发送 Tab 键", "Tab": "Tab", "Esc": "Esc", "Send Escape": "发送 Escape 键", - "Ctrl+Alt+Del": "Ctrl-Alt-Del", - "Send Ctrl-Alt-Del": "发送 Ctrl-Alt-Del 键", - "Shutdown/Reboot": "关机/重新启动", - "Shutdown/Reboot...": "关机/重新启动...", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "发送 Ctrl+Alt+Del 键", + "Shutdown/Reboot": "关机/重启", + "Shutdown/Reboot...": "关机/重启...", "Power": "电源", "Shutdown": "关机", - "Reboot": "重新启动", + "Reboot": "重启", "Reset": "重置", "Clipboard": "剪贴板", "Clear": "清除", "Fullscreen": "全屏", "Settings": "设置", + "Encrypt": "加密", "Shared Mode": "分享模式", "View Only": "仅查看", "Clip to Window": "限制/裁切窗口大小", "Scaling Mode:": "缩放模式:", "None": "无", "Local Scaling": "本地缩放", + "Local Downscaling": "降低本地尺寸", "Remote Resizing": "远程调整大小", "Advanced": "高级", + "Local Cursor": "本地光标", "Repeater ID:": "中继站 ID", "WebSocket": "WebSocket", - "Encrypt": "加密", "Host:": "主机:", "Port:": "端口:", "Path:": "路径:", "Automatic Reconnect": "自动重新连接", "Reconnect Delay (ms):": "重新连接间隔 (ms):", "Logging:": "日志级别:", - "Disconnect": "中断连接", + "Disconnect": "断开连接", "Connect": "连接", "Password:": "密码:", - "Cancel": "取消" + "Cancel": "取消", + "Canvas not supported.": "不支持 Canvas。" } \ No newline at end of file diff --git a/public/novnc/app/localization.js b/public/novnc/app/localization.js index 100901c9..7d7e6e6a 100644 --- a/public/novnc/app/localization.js +++ b/public/novnc/app/localization.js @@ -16,13 +16,19 @@ export class Localizer { this.language = 'en'; // Current dictionary of translations - this.dictionary = undefined; + this._dictionary = undefined; } // Configure suitable language based on user preferences - setup(supportedLanguages) { + async setup(supportedLanguages, baseURL) { this.language = 'en'; // Default: US English + this._dictionary = undefined; + this._setupLanguage(supportedLanguages); + await this._setupDictionary(baseURL); + } + + _setupLanguage(supportedLanguages) { /* * Navigator.languages only available in Chrome (32+) and FireFox (32+) * Fall back to navigator.language for other browsers @@ -40,12 +46,6 @@ export class Localizer { .replace("_", "-") .split("-"); - // Built-in default? - if ((userLang[0] === 'en') && - ((userLang[1] === undefined) || (userLang[1] === 'us'))) { - return; - } - // First pass: perfect match for (let j = 0; j < supportedLanguages.length; j++) { const supLang = supportedLanguages[j] @@ -64,7 +64,12 @@ export class Localizer { return; } - // Second pass: fallback + // Second pass: English fallback + if (userLang[0] === 'en') { + return; + } + + // Third pass pass: other fallback for (let j = 0;j < supportedLanguages.length;j++) { const supLang = supportedLanguages[j] .toLowerCase() @@ -84,10 +89,32 @@ export class Localizer { } } + async _setupDictionary(baseURL) { + if (baseURL) { + if (!baseURL.endsWith("/")) { + baseURL = baseURL + "/"; + } + } else { + baseURL = ""; + } + + if (this.language === "en") { + return; + } + + let response = await fetch(baseURL + this.language + ".json"); + if (!response.ok) { + throw Error("" + response.status + " " + response.statusText); + } + + this._dictionary = await response.json(); + } + // Retrieve localised text get(id) { - if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) { - return this.dictionary[id]; + if (typeof this._dictionary !== 'undefined' && + this._dictionary[id]) { + return this._dictionary[id]; } else { return id; } @@ -103,13 +130,20 @@ export class Localizer { return items.indexOf(searchElement) !== -1; } + function translateString(str) { + // We assume surrounding whitespace, and whitespace around line + // breaks is just for source formatting + str = str.split("\n").map(s => s.trim()).join(" ").trim(); + return self.get(str); + } + function translateAttribute(elem, attr) { - const str = self.get(elem.getAttribute(attr)); + const str = translateString(elem.getAttribute(attr)); elem.setAttribute(attr, str); } function translateTextNode(node) { - const str = self.get(node.data.trim()); + const str = translateString(node.data); node.data = str; } diff --git a/public/novnc/app/styles/base.css b/public/novnc/app/styles/base.css index fd78b79c..f83ad4b9 100644 --- a/public/novnc/app/styles/base.css +++ b/public/novnc/app/styles/base.css @@ -19,10 +19,23 @@ * 10000: Max (used for polyfills) */ +/* + * State variables (set on :root): + * + * noVNC_loading: Page is still loading + * noVNC_connecting: Connecting to server + * noVNC_reconnecting: Re-establishing a connection + * noVNC_connected: Connected to server (most common state) + * noVNC_disconnecting: Disconnecting from server + */ + +:root { + font-family: sans-serif; +} + body { margin:0; padding:0; - font-family: Helvetica; /*Background image with light grey curve.*/ background-color:#494949; background-repeat:no-repeat; @@ -78,144 +91,6 @@ html { 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } } -/* ---------------------------------------- - * Input Elements - * ---------------------------------------- - */ - -input:not([type]), -input[type=date], -input[type=datetime-local], -input[type=email], -input[type=month], -input[type=number], -input[type=password], -input[type=search], -input[type=tel], -input[type=text], -input[type=time], -input[type=url], -input[type=week], -textarea { - /* Disable default rendering */ - -webkit-appearance: none; - -moz-appearance: none; - background: none; - - margin: 2px; - padding: 2px; - border: 1px solid rgb(192, 192, 192); - border-radius: 5px; - color: black; - background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); -} - -input[type=button], -input[type=color], -input[type=reset], -input[type=submit], -select { - /* Disable default rendering */ - -webkit-appearance: none; - -moz-appearance: none; - background: none; - - margin: 2px; - padding: 2px; - border: 1px solid rgb(192, 192, 192); - border-bottom-width: 2px; - border-radius: 5px; - color: black; - background: linear-gradient(to top, rgb(255, 255, 255), rgb(240, 240, 240)); - - /* This avoids it jumping around when :active */ - vertical-align: middle; -} - -input[type=button], -input[type=color], -input[type=reset], -input[type=submit] { - padding-left: 20px; - padding-right: 20px; -} - -option { - color: black; - background: white; -} - -input:not([type]):focus, -input[type=button]:focus, -input[type=color]:focus, -input[type=date]:focus, -input[type=datetime-local]:focus, -input[type=email]:focus, -input[type=month]:focus, -input[type=number]:focus, -input[type=password]:focus, -input[type=reset]:focus, -input[type=search]:focus, -input[type=submit]:focus, -input[type=tel]:focus, -input[type=text]:focus, -input[type=time]:focus, -input[type=url]:focus, -input[type=week]:focus, -select:focus, -textarea:focus { - box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5); - border-color: rgb(74, 144, 217); - outline: none; -} - -input[type=button]::-moz-focus-inner, -input[type=color]::-moz-focus-inner, -input[type=reset]::-moz-focus-inner, -input[type=submit]::-moz-focus-inner { - border: none; -} - -input:not([type]):disabled, -input[type=button]:disabled, -input[type=color]:disabled, -input[type=date]:disabled, -input[type=datetime-local]:disabled, -input[type=email]:disabled, -input[type=month]:disabled, -input[type=number]:disabled, -input[type=password]:disabled, -input[type=reset]:disabled, -input[type=search]:disabled, -input[type=submit]:disabled, -input[type=tel]:disabled, -input[type=text]:disabled, -input[type=time]:disabled, -input[type=url]:disabled, -input[type=week]:disabled, -select:disabled, -textarea:disabled { - color: rgb(128, 128, 128); - background: rgb(240, 240, 240); -} - -input[type=button]:active, -input[type=color]:active, -input[type=reset]:active, -input[type=submit]:active, -select:active { - border-bottom-width: 1px; - margin-top: 3px; -} - -:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled), -:root:not(.noVNC_touch) input[type=color]:hover:not(:disabled), -:root:not(.noVNC_touch) input[type=reset]:hover:not(:disabled), -:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled), -:root:not(.noVNC_touch) select:hover:not(:disabled) { - background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); -} - /* ---------------------------------------- * WebKit centering hacks * ---------------------------------------- @@ -242,13 +117,15 @@ select:active { pointer-events: auto; } .noVNC_vcenter { - display: flex; + display: flex !important; flex-direction: column; justify-content: center; position: fixed; top: 0; left: 0; height: 100%; + margin: 0 !important; + padding: 0 !important; pointer-events: none; } .noVNC_vcenter > * { @@ -272,13 +149,20 @@ select:active { #noVNC_fallback_error { z-index: 1000; visibility: hidden; + /* Put a dark background in front of everything but the error, + and don't let mouse events pass through */ + background: rgba(0, 0, 0, 0.8); + pointer-events: all; } #noVNC_fallback_error.noVNC_open { visibility: visible; } #noVNC_fallback_error > div { - max-width: 90%; + max-width: calc(100vw - 30px - 30px); + max-height: calc(100vh - 30px - 30px); + overflow: auto; + padding: 15px; transition: 0.5s ease-in-out; @@ -317,7 +201,6 @@ select:active { } #noVNC_fallback_error .noVNC_stack { - max-height: 50vh; padding: 10px; margin: 10px; font-size: 0.8em; @@ -361,6 +244,9 @@ select:active { background-color: rgb(110, 132, 163); border-radius: 0 10px 10px 0; + user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; /* Disable iOS image long-press popup */ } #noVNC_control_bar.noVNC_open { box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); @@ -433,38 +319,50 @@ select:active { .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { transform: none; } +/* Larger touch area for the handle, used when a touch screen is available */ #noVNC_control_bar_handle div { position: absolute; right: -35px; top: 0; width: 50px; - height: 50px; -} -:root:not(.noVNC_touch) #noVNC_control_bar_handle div { + height: 100%; display: none; } +@media (any-pointer: coarse) { + #noVNC_control_bar_handle div { + display: initial; + } +} .noVNC_right #noVNC_control_bar_handle div { left: -35px; right: auto; } -#noVNC_control_bar .noVNC_scroll { +#noVNC_control_bar > .noVNC_scroll { max-height: 100vh; /* Chrome is buggy with 100% */ overflow-x: hidden; overflow-y: auto; - padding: 0 10px 0 5px; + padding: 0 10px; } -.noVNC_right #noVNC_control_bar .noVNC_scroll { - padding: 0 5px 0 10px; + +#noVNC_control_bar > .noVNC_scroll > * { + display: block; + margin: 10px auto; } /* Control bar hint */ -#noVNC_control_bar_hint { +#noVNC_hint_anchor { position: fixed; - left: calc(100vw - 50px); + right: -50px; + left: auto; +} +#noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor { + left: -50px; right: auto; - top: 50%; - transform: translateY(-50%) scale(0); +} +#noVNC_control_bar_hint { + position: relative; + transform: scale(0); width: 100px; height: 50%; max-height: 600px; @@ -477,61 +375,65 @@ select:active { border-radius: 10px; transition-delay: 0s; } -#noVNC_control_bar_anchor.noVNC_right #noVNC_control_bar_hint{ - left: auto; - right: calc(100vw - 50px); -} #noVNC_control_bar_hint.noVNC_active { visibility: visible; opacity: 1; transition-delay: 0.2s; - transform: translateY(-50%) scale(1); + transform: scale(1); +} +#noVNC_control_bar_hint.noVNC_notransition { + transition: none !important; } -/* General button style */ -.noVNC_button { - display: block; +/* Control bar buttons */ +#noVNC_control_bar .noVNC_button { padding: 4px 4px; - margin: 10px 0; vertical-align: middle; border:1px solid rgba(255, 255, 255, 0.2); border-radius: 6px; + background-color: transparent; + background-image: unset; /* we don't want the gradiant from input.css */ } -.noVNC_button.noVNC_selected { +#noVNC_control_bar .noVNC_button.noVNC_selected { border-color: rgba(0, 0, 0, 0.8); - background: rgba(0, 0, 0, 0.5); + background-color: rgba(0, 0, 0, 0.5); } -.noVNC_button:disabled { - opacity: 0.4; +#noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { + border-color: rgba(0, 0, 0, 0.4); + background-color: rgba(0, 0, 0, 0.2); } -.noVNC_button:focus { - outline: none; +#noVNC_control_bar .noVNC_button:not(:disabled):hover { + background-color: rgba(255, 255, 255, 0.2); } -.noVNC_button:active { +#noVNC_control_bar .noVNC_button:not(:disabled):active { padding-top: 5px; padding-bottom: 3px; } -/* Android browsers don't properly update hover state if touch events - * are intercepted, but focus should be safe to display */ -:root:not(.noVNC_touch) .noVNC_button.noVNC_selected:hover, -.noVNC_button.noVNC_selected:focus { - border-color: rgba(0, 0, 0, 0.4); - background: rgba(0, 0, 0, 0.2); +#noVNC_control_bar .noVNC_button.noVNC_hidden { + display: none !important; } -:root:not(.noVNC_touch) .noVNC_button:hover, -.noVNC_button:focus { - background: rgba(255, 255, 255, 0.2); -} -.noVNC_button.noVNC_hidden { - display: none; + +/* Android browsers don't properly update hover state if touch events are + * intercepted, like they are when clicking on the remote screen. */ +@media (any-pointer: coarse) { + #noVNC_control_bar .noVNC_button:not(:disabled):hover { + background-color: transparent; + } + #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { + border-color: rgba(0, 0, 0, 0.8); + background-color: rgba(0, 0, 0, 0.5); + } } + /* Panels */ .noVNC_panel { transform: translateX(25px); transition: 0.5s ease-in-out; + box-sizing: border-box; /* so max-width don't have to care about padding */ + max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ max-height: 100vh; /* Chrome is buggy with 100% */ overflow-x: hidden; overflow-y: auto; @@ -563,6 +465,17 @@ select:active { transform: translateX(-75px); } +.noVNC_panel > * { + display: block; + margin: 10px auto; +} +.noVNC_panel > *:first-child { + margin-top: 0 !important; +} +.noVNC_panel > *:last-child { + margin-bottom: 0 !important; +} + .noVNC_panel hr { border: none; border-top: 1px solid rgb(192, 192, 192); @@ -571,6 +484,11 @@ select:active { .noVNC_panel label { display: block; white-space: nowrap; + margin: 5px; +} + +.noVNC_panel li { + margin: 5px; } .noVNC_panel .noVNC_heading { @@ -581,7 +499,6 @@ select:active { padding-right: 8px; color: white; font-size: 20px; - margin-bottom: 10px; white-space: nowrap; } .noVNC_panel .noVNC_heading img { @@ -622,6 +539,12 @@ select:active { font-size: 13px; } +.noVNC_logo + hr { + /* Remove all but top border */ + border: none; + border-top: 1px solid rgba(255, 255, 255, 0.2); +} + :root:not(.noVNC_connected) #noVNC_view_drag_button { display: none; } @@ -630,8 +553,15 @@ select:active { :root:not(.noVNC_connected) #noVNC_mobile_buttons { display: none; } -:root:not(.noVNC_touch) #noVNC_mobile_buttons { - display: none; +@media not all and (any-pointer: coarse) { + /* FIXME: The button for the virtual keyboard is the only button in this + group of "mobile buttons". It is bad to assume that no touch + devices have physical keyboards available. Hopefully we can get + a media query for this: + https://github.com/w3c/csswg-drafts/issues/3871 */ + :root.noVNC_connected #noVNC_mobile_buttons { + display: none; + } } /* Extra manual keys */ @@ -642,7 +572,7 @@ select:active { #noVNC_modifiers { background-color: rgb(92, 92, 92); border: none; - padding: 0 10px; + padding: 10px; } /* Shutdown/Reboot */ @@ -663,13 +593,16 @@ select:active { :root:not(.noVNC_connected) #noVNC_clipboard_button { display: none; } -#noVNC_clipboard { - /* Full screen, minus padding and left and right margins */ - max-width: calc(100vw - 2*15px - 75px - 25px); -} #noVNC_clipboard_text { - width: 500px; + width: 360px; + min-width: 150px; + height: 160px; + min-height: 70px; + + box-sizing: border-box; max-width: 100%; + /* minus approximate height of title, height of subtitle, and margin */ + max-height: calc(100vh - 10em - 25px); } /* Settings */ @@ -677,7 +610,6 @@ select:active { } #noVNC_settings ul { list-style: none; - margin: 0px; padding: 0px; } #noVNC_setting_port { @@ -729,7 +661,7 @@ select:active { justify-content: center; align-content: center; - line-height: 25px; + line-height: 1.6; word-wrap: break-word; color: #fff; @@ -803,36 +735,32 @@ select:active { font-size: calc(25vw - 30px); } } -#noVNC_connect_button { - cursor: pointer; +#noVNC_connect_dlg div { + padding: 12px; - padding: 10px; - - color: white; background-color: rgb(110, 132, 163); border-radius: 12px; - text-align: center; font-size: 20px; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } -#noVNC_connect_button div { - margin: 2px; +#noVNC_connect_button { + width: 100%; padding: 5px 30px; - border: 1px solid rgb(83, 99, 122); - border-bottom-width: 2px; + + cursor: pointer; + + border-color: rgb(83, 99, 122); border-radius: 5px; + background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); + color: white; /* This avoids it jumping around when :active */ vertical-align: middle; } -#noVNC_connect_button div:active { - border-bottom-width: 1px; - margin-top: 3px; -} -:root:not(.noVNC_touch) #noVNC_connect_button div:hover { +#noVNC_connect_button:hover { background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); } @@ -841,6 +769,23 @@ select:active { height: 1.3em; } +/* ---------------------------------------- + * Server verification Dialog + * ---------------------------------------- + */ + +#noVNC_verify_server_dlg { + position: relative; + + transform: translateY(-50px); +} +#noVNC_verify_server_dlg.noVNC_open { + transform: translateY(0); +} +#noVNC_fingerprint_block { + margin: 10px; +} + /* ---------------------------------------- * Password Dialog * ---------------------------------------- @@ -854,12 +799,8 @@ select:active { #noVNC_credentials_dlg.noVNC_open { transform: translateY(0); } -#noVNC_credentials_dlg ul { - list-style: none; - margin: 0px; - padding: 0px; -} -.noVNC_hidden { +#noVNC_username_block.noVNC_hidden, +#noVNC_password_block.noVNC_hidden { display: none; } @@ -871,7 +812,11 @@ select:active { /* Transition screen */ #noVNC_transition { - display: none; + transition: 0.5s ease-in-out; + + display: flex; + opacity: 0; + visibility: hidden; position: fixed; top: 0; @@ -892,7 +837,8 @@ select:active { :root.noVNC_connecting #noVNC_transition, :root.noVNC_disconnecting #noVNC_transition, :root.noVNC_reconnecting #noVNC_transition { - display: flex; + opacity: 1; + visibility: visible; } :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { display: none; @@ -908,6 +854,12 @@ select:active { background-color: #313131; border-bottom-right-radius: 800px 600px; /*border-top-left-radius: 800px 600px;*/ + + /* If selection isn't disabled, long-pressing stuff in the sidebar + can accidentally select the container or the canvas. This can + happen when attempting to move the handle. */ + user-select: none; + -webkit-user-select: none; } #noVNC_keyboardinput { @@ -935,7 +887,7 @@ select:active { .noVNC_logo { color:yellow; font-family: 'Orbitron', 'OrbitronTTF', sans-serif; - line-height:90%; + line-height: 0.9; text-shadow: 0.1em 0.1em 0 black; } .noVNC_logo span{ diff --git a/public/novnc/app/styles/input.css b/public/novnc/app/styles/input.css new file mode 100644 index 00000000..dc345aab --- /dev/null +++ b/public/novnc/app/styles/input.css @@ -0,0 +1,281 @@ +/* + * noVNC general input element CSS + * Copyright (C) 2022 The noVNC Authors + * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) + * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). + */ + +/* + * Common for all inputs + */ +input, input::file-selector-button, button, select, textarea { + /* Respect standard font settings */ + font: inherit; + + /* Disable default rendering */ + appearance: none; + background: none; + + padding: 5px; + border: 1px solid rgb(192, 192, 192); + border-radius: 5px; + color: black; + --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); + background-image: var(--bg-gradient); +} + +/* + * Buttons + */ +input[type=button], +input[type=color], +input[type=image], +input[type=reset], +input[type=submit], +input::file-selector-button, +button, +select { + border-bottom-width: 2px; + + /* This avoids it jumping around when :active */ + vertical-align: middle; + margin-top: 0; + + padding-left: 20px; + padding-right: 20px; + + /* Disable Chrome's touch tap highlight */ + -webkit-tap-highlight-color: transparent; +} + +/* + * Select dropdowns + */ +select { + --select-arrow: url('data:image/svg+xml;utf8, \ + \ + \ + '); + background-image: var(--select-arrow), var(--bg-gradient); + background-position: calc(100% - 7px), left top; + background-repeat: no-repeat; + padding-right: calc(2*7px + 8px); + padding-left: 7px; +} +/* FIXME: :active isn't set when the Clipboard +

+ Edit clipboard content in the textarea below. +

-
- - + title="Full Screen">
+
+ Settings +
    -
  • - Settings -
  • @@ -263,39 +247,69 @@
-
- +
+
+
+
+
- -
- Connect -
+ +
+ +
+ +
+
+
+ Server identity +
+
+ The server has provided the following identifying information: +
+
+ Fingerprint: + +
+
+ Please verify that the information is correct and press + "Approve". Otherwise press "Reject". +
+
+ + +
+
+
+
-
    -
  • - - -
  • -
  • - - -
  • -
  • - -
  • -
+
+ Credentials +
+
+ + +
+
+ + +
+
+ +
diff --git a/public/scripts/agent-desktop-0.0.2-min.js b/public/scripts/agent-desktop-0.0.2-min.js index 86fcbd29..9bfbf813 100644 --- a/public/scripts/agent-desktop-0.0.2-min.js +++ b/public/scripts/agent-desktop-0.0.2-min.js @@ -1 +1 @@ -Uint8Array.prototype.slice||Object.defineProperty(Uint8Array.prototype,"slice",{value:function(e,t){return new Uint8Array(Array.prototype.slice.call(this,e,t))}});var CreateAgentRemoteDesktop=function(e,t){var g={},p=("string"==typeof(g.CanvasId=e)&&(g.CanvasId=Q(e)),g.Canvas=g.CanvasId.getContext("2d"),g.scrolldiv=t,g.State=0,g.PendingOperations=[],g.tilesReceived=0,g.TilesDrawn=0,g.KillDraw=0,g.ipad=!1,g.tabletKeyboardVisible=!1,g.LastX=0,g.LastY=0,g.touchenabled=0,g.submenuoffset=0,g.touchtimer=null,g.TouchArray={},g.connectmode=0,g.connectioncount=0,g.rotation=0,g.protocol=2,g.debugmode=0,g.firstUpKeys=[],g.stopInput=!1,g.localKeyMap=!0,g.remoteKeyMap=!1,g.pressedKeys=[],g.sessionid=0,g.oldie=!1,g.ImageType=1,g.CompressionLevel=50,g.ScalingLevel=1024,g.FrameRateTimer=100,g.SwapMouse=!1,g.UseExtendedKeyFlag=!0,g.FirstDraw=!1,g.onRemoteInputLockChanged=null,g.RemoteInputLock=null,g.onKeyboardStateChanged=null,g.KeyboardState=0,g.ScreenWidth=960,g.ScreenHeight=701,g.width=960,g.height=960,g.displays=null,g.selectedDisplay=null,g.onScreenSizeChange=null,g.onMessage=null,g.onConnectCountChanged=null,g.onDebugMessage=null,g.onTouchEnabledChanged=null,g.onDisplayinfo=null,!(g.accumulator=null)),S="default",v=(g.mouseCursorActive=function(e){p!=e&&(p=e,g.CanvasId.style.cursor=1==e?S:"default")},["default","progress","crosshair","pointer","help","text","no-drop","move","nesw-resize","ns-resize","nwse-resize","w-resize","alias","wait","none","not-allowed","col-resize","row-resize","copy","zoom-in","zoom-out"]),a=(g.Start=function(){g.State=0,g.accumulator=null},g.Stop=function(){g.setRotation(0),g.UnGrabKeyInput(),g.UnGrabMouseInput(),g.touchenabled=0,null!=g.onScreenSizeChange&&g.onScreenSizeChange(g,g.ScreenWidth,g.ScreenHeight,g.CanvasId),g.Canvas.clearRect(0,0,g.CanvasId.width,g.CanvasId.height)},g.xxStateChange=function(e){g.State!=e&&(g.State=e,g.CanvasId.style.cursor="default",0===e)&&g.Stop()},g.send=function(e){2>32)+g.intToStr(32&o)):(g.recordedSize+=n.length,g.shortToStr(e)+g.shortToStr(t)+g.intToStr(n.length)+g.intToStr(o>>32)+g.intToStr(32&o)+n)}return g.SendKeyMsg=function(e,t){var n,o;null!=e&&(t=t||window.event,n=!1,0==(n=(g.UseExtendedKeyFlag||1==urlargs.extkeys)&&"string"==typeof t.code&&(t.code.startsWith("Arrow")||0<=r.indexOf(t.code))?!0:n)&&t.code&&0==t.code.startsWith("NumPad")&&0==g.localKeyMap?null!=(o=(o=t).code.startsWith("Key")&&4==o.code.length?o.code.charCodeAt(3):o.code.startsWith("Digit")&&6==o.code.length?o.code.charCodeAt(5):o.code.startsWith("Numpad")&&7==o.code.length?o.code.charCodeAt(6)+48:a[o.code])&&g.SendKeyMsgKC(e,o,n):(59==(o=t.keyCode)?o=186:173==o?o=189:61==o&&(o=187),g.SendKeyMsgKC(e,o,n)))},g.SendRemoteInputLock=function(e){g.send(String.fromCharCode(0,87,0,5,e))},g.SendMessage=function(e){3==g.State&&g.send(String.fromCharCode(0,17)+g.shortToStr(4+e.length)+e)},g.SendKeyMsgKC=function(e,t,n){if(3==g.State)if("object"==typeof e)for(var o in e)g.SendKeyMsgKC(e[o][0],e[o][1],e[o][2]);else{1==e?-1==g.pressedKeys.indexOf(t)&&g.pressedKeys.unshift(t):2==e&&-1!=(o=g.pressedKeys.indexOf(t))&&g.pressedKeys.splice(o,1),0>8),255-(255&Math.abs(r))):(s=r>>8,255&r),String.fromCharCode(0,g.InputType.MOUSE,0,12,0,0,n/256&255,255&n,o/256&255,255&o,s,i)):String.fromCharCode(0,g.InputType.MOUSE,0,10,0,e==g.KeyAction.DOWN?a:2*a&255,n/256&255,255&n,o/256&255,255&o),g.Action==g.KeyAction.NONE?0==g.Alternate||g.ipad?(g.send(t),g.Alternate=1):g.Alternate=0:g.send(t))},g.GetDisplayNumbers=function(){g.send(String.fromCharCode(0,11,0,4))},g.SetDisplay=function(e){g.send(String.fromCharCode(0,12,0,6,e>>8,255&e))},g.intToStr=function(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,255&e)},g.shortToStr=function(e){return String.fromCharCode(e>>8&255,255&e)},g.onResize=function(){0==g.ScreenWidth||0==g.ScreenHeight||g.Canvas.canvas.width==g.ScreenWidth&&g.Canvas.canvas.height==g.ScreenHeight||(g.FirstDraw&&(g.Canvas.canvas.width=g.ScreenWidth,g.Canvas.canvas.height=g.ScreenHeight,g.Canvas.fillRect(0,0,g.ScreenWidth,g.ScreenHeight),null!=g.onScreenSizeChange)&&g.onScreenSizeChange(g,g.ScreenWidth,g.ScreenHeight,g.CanvasId),g.FirstDraw=!1,1>32)+p.intToStr(32&o)):(p.recordedSize+=n.length,p.shortToStr(e)+p.shortToStr(t)+p.intToStr(n.length)+p.intToStr(o>>32)+p.intToStr(32&o)+n)}return p.checkAltGr=function(e,t,n){return e._altGrArmed&&(e._altGrArmed=!1,clearTimeout(e._altGrTimeout),"AltRight"===t.code)&&t.timeStamp-e._altGrCtrlTime<50?(e.SendKeyMsgKC(n,225,!1),!0):!("ControlLeft"!==t.code||17 in e.pressedKeys||(e._altGrArmed=!0,e._altGrCtrlTime=t.timeStamp,1!=n)||(e._altGrTimeout=setTimeout(e._handleAltGrTimeout.bind(e),100),0))},p._handleAltGrTimeout=function(){p._altGrArmed=!1,clearTimeout(p._altGrTimeout),p.SendKeyMsgKC(1,17,!1)},p.SendRemoteInputLock=function(e){p.send(String.fromCharCode(0,87,0,5,e))},p.SendMessage=function(e){3==p.State&&p.send(String.fromCharCode(0,17)+p.shortToStr(4+e.length)+e)},p.SendKeyMsgKC=function(e,t,n){if(3==p.State)if("object"==typeof e)for(var o in e)p.SendKeyMsgKC(e[o][0],e[o][1],e[o][2]);else{1==e?-1==p.pressedKeys.indexOf(t)&&p.pressedKeys.unshift(t):2==e&&-1!=(o=p.pressedKeys.indexOf(t))&&p.pressedKeys.splice(o,1),0>8),255-(255&Math.abs(r))):(s=r>>8,255&r),String.fromCharCode(0,p.InputType.MOUSE,0,12,0,0,n/256&255,255&n,o/256&255,255&o,s,i)):String.fromCharCode(0,p.InputType.MOUSE,0,10,0,e==p.KeyAction.DOWN?a:2*a&255,n/256&255,255&n,o/256&255,255&o),p.Action==p.KeyAction.NONE?0==p.Alternate||p.ipad?(p.send(t),p.Alternate=1):p.Alternate=0:p.send(t))},p.GetDisplayNumbers=function(){p.send(String.fromCharCode(0,11,0,4))},p.SetDisplay=function(e){p.send(String.fromCharCode(0,12,0,6,e>>8,255&e))},p.intToStr=function(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,255&e)},p.shortToStr=function(e){return String.fromCharCode(e>>8&255,255&e)},p.onResize=function(){0==p.ScreenWidth||0==p.ScreenHeight||p.Canvas.canvas.width==p.ScreenWidth&&p.Canvas.canvas.height==p.ScreenHeight||(p.FirstDraw&&(p.Canvas.canvas.width=p.ScreenWidth,p.Canvas.canvas.height=p.ScreenHeight,p.Canvas.fillRect(0,0,p.ScreenWidth,p.ScreenHeight),null!=p.onScreenSizeChange)&&p.onScreenSizeChange(p,p.ScreenWidth,p.ScreenHeight,p.CanvasId),p.FirstDraw=!1,1 2) { console.log('CMD', cmd, cmdsize, X, Y); } + // Fix for view being too large for String.fromCharCode.apply() + var chunkSize = 10000; + let result = ''; + for (let i = 0; i < view.length; i += chunkSize) { result += String.fromCharCode.apply(null, view.slice(i, i + chunkSize)); } // Record the command if needed if (obj.recordedData != null) { if (cmdsize > 65000) { - obj.recordedData.push(recordingEntry(2, 1, obj.shortToStr(27) + obj.shortToStr(8) + obj.intToStr(cmdsize) + obj.shortToStr(cmd) + obj.shortToStr(0) + obj.shortToStr(0) + obj.shortToStr(0) + String.fromCharCode.apply(null, view))); + obj.recordedData.push(recordingEntry(2, 1, obj.shortToStr(27) + obj.shortToStr(8) + obj.intToStr(cmdsize) + obj.shortToStr(cmd) + obj.shortToStr(0) + obj.shortToStr(0) + obj.shortToStr(0) + result)); } else { - obj.recordedData.push(recordingEntry(2, 1, String.fromCharCode.apply(null, view))); + obj.recordedData.push(recordingEntry(2, 1, result)); } } @@ -403,7 +413,16 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { if (!event) { event = window.event; } var extendedKey = false; // Test feature, add ?extkeys=1 to url to use. - if ((obj.UseExtendedKeyFlag || (urlargs.extkeys == 1)) && (typeof event.code == 'string') && (event.code.startsWith('Arrow') || (extendedKeyTable.indexOf(event.code) >= 0))) { extendedKey = true; } + + if ((obj.UseExtendedKeyFlag || (urlargs.extkeys == 1)) && (typeof event.code == 'string') && (event.code.startsWith('Arrow') || (extendedKeyTable.indexOf(event.code) >= 0))) { + extendedKey = true; + } + + if (obj.isWindowsBrowser) { + if( obj.checkAltGr(obj, event, action) ) { + return; + }; + } if ((extendedKey == false) && event.code && (event.code.startsWith('NumPad') == false) && (obj.localKeyMap == false)) { // Convert "event.code" into a scancode. This works the same regardless of the keyboard language. @@ -421,6 +440,44 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { } } + const ControlLeftKc = 17; + const AltGrKc = 225; + //return true: Key is alredy handled. + obj.checkAltGr = function (obj, event, action) { + // Windows doesn't have a proper AltGr, but handles it using + // fake Ctrl+Alt. However the remote end might not be Windows, + // so we need to merge those into a single AltGr event. We + // detect this case by seeing the two key events directly after + // each other with a very short time between them (<50ms). + if (obj._altGrArmed) { + obj._altGrArmed = false; + clearTimeout(obj._altGrTimeout); + + if ((event.code === "AltRight") && ((event.timeStamp - obj._altGrCtrlTime) < 50)) { + //AltGr detected. + obj.SendKeyMsgKC( action, AltGrKc, false); + return true; + } + } + + // Possible start of AltGr sequence? + if ((event.code === "ControlLeft") && !(ControlLeftKc in obj.pressedKeys)) { + obj._altGrArmed = true; + obj._altGrCtrlTime = event.timeStamp; + if( action == 1 ) { + obj._altGrTimeout = setTimeout(obj._handleAltGrTimeout.bind(obj), 100); + return true; + } + } + return false; + } + + obj._handleAltGrTimeout = function () { //Windows and no Ctrl+Alt -> send only Ctrl. + obj._altGrArmed = false; + clearTimeout(obj._altGrTimeout); + obj.SendKeyMsgKC( 1, ControlLeftKc, false); // (KeyDown, "ControlLeft", false) + } + // Send remote input lock. 0 = Unlock, 1 = Lock, 2 = Query obj.SendRemoteInputLock = function (code) { obj.send(String.fromCharCode(0x00, 87, 0x00, 0x05, code)); } @@ -456,7 +513,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { obj.SendKeyUnicode = function (action, val) { if (obj.State != 3) return; - if (obj.debugmode > 0) { console.log('Sending UnicodeKey ' + val); } + if (obj.debugmode > 0) { console.log('Sending UnicodeKey ' + val + ', action ' + action); } obj.send(String.fromCharCode(0x00, obj.InputType.KEYUNICODE, 0x00, 0x07, (action - 1)) + ShortToStr(val)); } @@ -521,7 +578,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { var Delta = 0; if (Action == obj.KeyAction.UP || Action == obj.KeyAction.DOWN) { if (event.which) { ((event.which == 1) ? (Button = obj.MouseButton.LEFT) : ((event.which == 2) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); } - else if (event.button) { ((event.button == 0) ? (Button = obj.MouseButton.LEFT) : ((event.button == 1) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); } + else if (typeof event.button == 'number') { ((event.button == 0) ? (Button = obj.MouseButton.LEFT) : ((event.button == 1) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); } } else if (Action == obj.KeyAction.SCROLL) { if (event.detail) { Delta = (-1 * (event.detail * 120)); } else if (event.wheelDelta) { Delta = (event.wheelDelta * 3); } diff --git a/public/scripts/agent-rdp-0.0.1-min.js b/public/scripts/agent-rdp-0.0.1-min.js index c8f14c59..dc3b7f4b 100644 --- a/public/scripts/agent-rdp-0.0.1-min.js +++ b/public/scripts/agent-rdp-0.0.1-min.js @@ -1 +1 @@ -var CreateRDPDesktop=function(e,a){var o={m:{KeyAction:{NONE:0,DOWN:1,UP:2,SCROLL:3,EXUP:4,EXDOWN:5,DBLCLICK:6}},State:0},i=(o.canvas=Q(e),"string"==typeof(o.CanvasId=e)&&(o.CanvasId=Q(e)),o.Canvas=o.CanvasId.getContext("2d"),o.ScreenWidth=o.width=1280,o.ScreenHeight=o.height=1024,o.m.onClipboardChanged=null,!(o.onConsoleMessageChange=null)),r="default";function n(e){return(!0===o.m.SwapMouse?[2,0,1,0,0]:[1,0,2,0,0])[e]}function c(e){o.State!=e&&(o.State=e,null!=o.onStateChanged)&&o.onStateChanged(o,o.State)}function s(e){var t=o.Canvas.canvas.height/o.CanvasId.clientHeight,n=o.Canvas.canvas.width/o.CanvasId.clientWidth,s=function(e){var t=Array(2);for(t[0]=t[1]=0;e;)t[0]+=e.offsetLeft,t[1]+=e.offsetTop,e=e.offsetParent;return t}(o.Canvas.canvas),n=(e.pageX-s[0])*n,s=(e.pageY-s[1])*t;return e.addx&&(n+=e.addx),e.addy&&(s+=e.addy),{x:n,y:s}}o.mouseCursorActive=function(e){i!=e&&(i=e,o.CanvasId.style.cursor=1==e?r:"default")},o.Start=function(e,t,n){c(1),o.nodeid=e,o.port=t;var s={savepass:(o.credentials=n).savecred,useServerCreds:n.servercred,width:n.width,height:n.height,flags:n.flags,workingDir:n.workdir,alternateShell:n.altshell};n.width&&n.height&&(s.width=o.ScreenWidth=o.width=n.width,s.height=o.ScreenHeight=o.height=n.height,delete n.width,delete n.height),o.render=new Mstsc.Canvas.create(o.canvas),o.socket=new WebSocket("wss://"+window.location.host+a+"mstscrelay.ashx"),o.socket.binaryType="arraybuffer",o.socket.onopen=function(){c(2),o.socket.send(JSON.stringify(["infos",{ip:o.nodeid,port:o.port,screen:{width:o.width,height:o.height},domain:n.domain,username:n.username,password:n.password,options:s,locale:Mstsc.locale()}]))},o.socket.onmessage=function(e){if("string"==typeof e.data){var t=JSON.parse(e.data);switch(t[0]){case"rdp-connect":c(3),o.rotation=0,o.Canvas.setTransform(1,0,0,1,0,0),o.Canvas.canvas.width=o.ScreenWidth,o.Canvas.canvas.height=o.ScreenHeight,o.Canvas.fillRect(0,0,o.ScreenWidth,o.ScreenHeight),null!=o.m.onScreenSizeChange&&o.m.onScreenSizeChange(o,o.ScreenWidth,o.ScreenHeight,o.CanvasId);break;case"rdp-bitmap":null!=o.bitmapData&&((n=t[1]).data=o.bitmapData,delete o.bitmapData,o.render.update(n));break;case"rdp-pointer":var n=t[1];r=n,i&&(o.CanvasId.style.cursor=n);break;case"rdp-close":o.Stop();break;case"rdp-error":switch(o.consoleMessageTimeout=5,o.consoleMessage=t[1],delete o.consoleMessageArgs,2o.ScreenWidth||t.y>o.ScreenHeight))return o.mouseNagleData=["mouse",t.x,t.y,0,!1],null==o.mouseNagleTimer&&(o.mouseNagleTimer=setTimeout(function(){o.socket.send(JSON.stringify(o.mouseNagleData)),o.mouseNagleTimer=null},50)),e.preventDefault(),!1}},o.m.mouseup=function(e){if(o.socket&&3==o.State){var t=s(e);if(!(t.x<0||t.y<0||t.x>o.ScreenWidth||t.y>o.ScreenHeight))return null!=o.mouseNagleTimer&&(clearTimeout(o.mouseNagleTimer),o.mouseNagleTimer=null),o.socket.send(JSON.stringify(["mouse",t.x,t.y,n(e.button),!1])),e.preventDefault(),!1}},o.m.mousedown=function(e){if(o.socket&&3==o.State){var t=s(e);if(!(t.x<0||t.y<0||t.x>o.ScreenWidth||t.y>o.ScreenHeight))return null!=o.mouseNagleTimer&&(clearTimeout(o.mouseNagleTimer),o.mouseNagleTimer=null),o.socket.send(JSON.stringify(["mouse",t.x,t.y,n(e.button),!0])),e.preventDefault(),!1}},o.m.handleKeyUp=function(e){if(o.socket&&3==o.State)return o.socket.send(JSON.stringify(["scancode",Mstsc.scancode(e),!1])),e.preventDefault(),!1},o.m.handleKeyDown=function(e){if(o.socket&&3==o.State)return o.socket.send(JSON.stringify(["scancode",Mstsc.scancode(e),!0])),e.preventDefault(),!1},o.m.mousewheel=function(e){if(o.socket&&3==o.State){var t,n=s(e);if(!(n.x<0||n.y<0||n.x>o.ScreenWidth||n.y>o.ScreenHeight))return null!=o.mouseNagleTimer&&(clearTimeout(o.mouseNagleTimer),o.mouseNagleTimer=null),t=0,e.detail?t=120*e.detail:e.wheelDelta&&(t=3*e.wheelDelta),o.m.ReverseMouseWheel&&(t*=-1),0!=t&&o.socket.send(JSON.stringify(["wheel",n.x,n.y,t,!1,!1])),e.preventDefault(),!1}},o.m.SendStringUnicode=function(e){o.socket&&3==o.State&&o.socket.send(JSON.stringify(["utype",e]))},o.m.SendKeyMsgKC=function(e,t,n){if(3==o.State)if("object"==typeof e)for(var s in e)o.m.SendKeyMsgKC(e[s][0],e[s][1],e[s][2]);else{t=d[t];null!=t&&o.socket.send(JSON.stringify(["scancode",t,0!=(1&e)]))}},o.m.mousedblclick=function(){},o.m.handleKeyPress=function(){},o.m.setRotation=function(){},o.m.sendcad=function(){o.socket.send(JSON.stringify(["scancode",29,!0])),o.socket.send(JSON.stringify(["scancode",56,!0])),o.socket.send(JSON.stringify(["scancode",57427,!0])),o.socket.send(JSON.stringify(["scancode",57427,!1])),o.socket.send(JSON.stringify(["scancode",56,!1])),o.socket.send(JSON.stringify(["scancode",29,!1]))};var d={9:15,16:42,17:29,18:56,27:1,33:57417,34:57425,35:57423,36:57415,37:57419,38:57416,39:57421,40:57424,44:57399,45:57426,46:57427,65:30,66:48,67:46,68:32,69:18,70:33,71:34,72:35,73:23,74:36,75:37,76:38,77:50,78:49,79:24,80:25,81:16,82:19,83:31,84:20,85:22,86:47,87:17,88:45,89:21,90:44,91:57435,112:59,113:60,114:61,115:62,116:63,117:64,118:65,119:66,120:67,121:68,122:87,123:88};return o} \ No newline at end of file +var CreateRDPDesktop=function(e,a){var o={m:{KeyAction:{NONE:0,DOWN:1,UP:2,SCROLL:3,EXUP:4,EXDOWN:5,DBLCLICK:6}},State:0},i=(o.canvas=Q(e),"string"==typeof(o.CanvasId=e)&&(o.CanvasId=Q(e)),o.Canvas=o.CanvasId.getContext("2d"),o.ScreenWidth=o.width=1280,o.ScreenHeight=o.height=1024,o.m.onClipboardChanged=null,!(o.onConsoleMessageChange=null)),r="default";function n(e){return(!0===o.m.SwapMouse?[2,0,1,0,0]:[1,0,2,0,0])[e]}function c(e){o.State!=e&&(o.State=e,null!=o.onStateChanged)&&o.onStateChanged(o,o.State)}function s(e){var t=o.Canvas.canvas.height/o.CanvasId.clientHeight,n=o.Canvas.canvas.width/o.CanvasId.clientWidth,s=(e=>{var t=Array(2);for(t[0]=t[1]=0;e;)t[0]+=e.offsetLeft,t[1]+=e.offsetTop,e=e.offsetParent;return t})(o.Canvas.canvas),n=(e.pageX-s[0])*n,s=(e.pageY-s[1])*t;return e.addx&&(n+=e.addx),e.addy&&(s+=e.addy),{x:n,y:s}}o.mouseCursorActive=function(e){i!=e&&(i=e,o.CanvasId.style.cursor=1==e?r:"default")},o.Start=function(e,t,n){c(1),o.nodeid=e,o.port=t;var s={savepass:(o.credentials=n).savecred,useServerCreds:n.servercred,width:n.width,height:n.height,flags:n.flags,workingDir:n.workdir,alternateShell:n.altshell};n.width&&n.height&&(s.width=o.ScreenWidth=o.width=n.width,s.height=o.ScreenHeight=o.height=n.height,delete n.width,delete n.height),o.render=new Mstsc.Canvas.create(o.canvas),o.socket=new WebSocket("wss://"+window.location.host+a+"mstscrelay.ashx"),o.socket.binaryType="arraybuffer",o.socket.onopen=function(){c(2),o.socket.send(JSON.stringify(["infos",{ip:o.nodeid,port:o.port,screen:{width:o.width,height:o.height},domain:n.domain,username:n.username,password:n.password,options:s,locale:Mstsc.locale()}]))},o.socket.onmessage=function(e){if("string"==typeof e.data){var t=JSON.parse(e.data);switch(t[0]){case"rdp-connect":c(3),o.rotation=0,o.Canvas.setTransform(1,0,0,1,0,0),o.Canvas.canvas.width=o.ScreenWidth,o.Canvas.canvas.height=o.ScreenHeight,o.Canvas.fillRect(0,0,o.ScreenWidth,o.ScreenHeight),null!=o.m.onScreenSizeChange&&o.m.onScreenSizeChange(o,o.ScreenWidth,o.ScreenHeight,o.CanvasId);break;case"rdp-bitmap":null!=o.bitmapData&&((n=t[1]).data=o.bitmapData,delete o.bitmapData,o.render.update(n));break;case"rdp-pointer":var n=t[1];r=n,i&&(o.CanvasId.style.cursor=n);break;case"rdp-close":o.Stop();break;case"rdp-error":switch(o.consoleMessageTimeout=5,o.consoleMessage=t[1],delete o.consoleMessageArgs,2o.ScreenWidth||t.y>o.ScreenHeight))return o.mouseNagleData=["mouse",t.x,t.y,0,!1],null==o.mouseNagleTimer&&(o.mouseNagleTimer=setTimeout(function(){o.socket.send(JSON.stringify(o.mouseNagleData)),o.mouseNagleTimer=null},50)),e.preventDefault(),!1}},o.m.mouseup=function(e){if(o.socket&&3==o.State){var t=s(e);if(!(t.x<0||t.y<0||t.x>o.ScreenWidth||t.y>o.ScreenHeight))return null!=o.mouseNagleTimer&&(clearTimeout(o.mouseNagleTimer),o.mouseNagleTimer=null),o.socket.send(JSON.stringify(["mouse",t.x,t.y,n(e.button),!1])),e.preventDefault(),!1}},o.m.mousedown=function(e){if(o.socket&&3==o.State){var t=s(e);if(!(t.x<0||t.y<0||t.x>o.ScreenWidth||t.y>o.ScreenHeight))return null!=o.mouseNagleTimer&&(clearTimeout(o.mouseNagleTimer),o.mouseNagleTimer=null),o.socket.send(JSON.stringify(["mouse",t.x,t.y,n(e.button),!0])),e.preventDefault(),!1}},o.m.handleKeyUp=function(e){if(o.socket&&3==o.State)return o.socket.send(JSON.stringify(["scancode",Mstsc.scancode(e),!1])),e.preventDefault(),!1},o.m.handleKeyDown=function(e){if(o.socket&&3==o.State)return o.socket.send(JSON.stringify(["scancode",Mstsc.scancode(e),!0])),e.preventDefault(),!1},o.m.mousewheel=function(e){if(o.socket&&3==o.State){var t,n=s(e);if(!(n.x<0||n.y<0||n.x>o.ScreenWidth||n.y>o.ScreenHeight))return null!=o.mouseNagleTimer&&(clearTimeout(o.mouseNagleTimer),o.mouseNagleTimer=null),t=0,e.detail?t=120*e.detail:e.wheelDelta&&(t=3*e.wheelDelta),o.m.ReverseMouseWheel&&(t*=-1),0!=t&&o.socket.send(JSON.stringify(["wheel",n.x,n.y,t,!1,!1])),e.preventDefault(),!1}},o.m.SendStringUnicode=function(e){o.socket&&3==o.State&&o.socket.send(JSON.stringify(["utype",e]))},o.m.SendKeyMsgKC=function(e,t,n){if(3==o.State)if("object"==typeof e)for(var s in e)o.m.SendKeyMsgKC(e[s][0],e[s][1],e[s][2]);else{t=d[t];null!=t&&o.socket.send(JSON.stringify(["scancode",t,0!=(1&e)]))}},o.m.mousedblclick=function(){},o.m.handleKeyPress=function(){},o.m.setRotation=function(){},o.m.sendcad=function(){o.socket.send(JSON.stringify(["scancode",29,!0])),o.socket.send(JSON.stringify(["scancode",56,!0])),o.socket.send(JSON.stringify(["scancode",57427,!0])),o.socket.send(JSON.stringify(["scancode",57427,!1])),o.socket.send(JSON.stringify(["scancode",56,!1])),o.socket.send(JSON.stringify(["scancode",29,!1]))};var d={9:15,16:42,17:29,18:56,27:1,33:57417,34:57425,35:57423,36:57415,37:57419,38:57416,39:57421,40:57424,44:57399,45:57426,46:57427,65:30,66:48,67:46,68:32,69:18,70:33,71:34,72:35,73:23,74:36,75:37,76:38,77:50,78:49,79:24,80:25,81:16,82:19,83:31,84:20,85:22,86:47,87:17,88:45,89:21,90:44,91:57435,112:59,113:60,114:61,115:62,116:63,117:64,118:65,119:66,120:67,121:68,122:87,123:88};return o} \ No newline at end of file diff --git a/public/scripts/agent-redir-ws-0.1.1-min.js b/public/scripts/agent-redir-ws-0.1.1-min.js index 89bbc732..d7f32b38 100644 --- a/public/scripts/agent-redir-ws-0.1.1-min.js +++ b/public/scripts/agent-redir-ws-0.1.1-min.js @@ -1 +1 @@ -var CreateAgentRedirect=function(e,t,n,o,a,c){var s={};function l(){1==s.webSwitchOk&&1==s.webRtcActive&&(s.latency.current=-1,s.sendCtrlMsg('{"ctrlChannel":"102938","type":"webrtc0"}'),s.sendCtrlMsg('{"ctrlChannel":"102938","type":"webrtc1"}'),null!=s.onStateChanged)&&s.onStateChanged(s,s.State)}((s.m=t).parent=s).meshserver=e,s.authCookie=o,s.rauthCookie=a,s.State=0,s.nodeid=null,s.options=null,s.socket=null,s.connectstate=-1,s.tunnelid=Math.random().toString(36).substring(2),s.protocol=t.protocol,s.onStateChanged=null,s.ctrlMsgAllowed=!0,s.attemptWebRTC=!1,s.webRtcActive=!1,s.webSwitchOk=!1,s.webchannel=null,s.webrtc=null,s.debugmode=0,s.serverIsRecording=!1,s.urlname="meshrelay.ashx",s.latency={lastSend:null,current:-1,callback:null},null==c&&(c="/"),s.consoleMessage=null,s.onConsoleMessageChange=null,s.metadata=null,s.onMetadataChange=null,s.Start=function(e){var t=window.location.protocol.replace("http","ws")+"//"+window.location.host+window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/"))+"/"+s.urlname+"?browser=1&p="+s.protocol+(e?"&nodeid="+e:"")+"&id="+s.tunnelid;null!=o&&""!=o&&(t+="&auth="+o),null!=urlargs&&null!=urlargs.slowrelay&&(t+="&slowrelay="+urlargs.slowrelay),s.nodeid=e,s.connectstate=0,s.socket=new WebSocket(t),s.socket.binaryType="arraybuffer",s.socket.onopen=s.xxOnSocketConnected,s.socket.onmessage=s.xxOnMessage,s.socket.onerror=function(e){},s.socket.onclose=s.xxOnSocketClosed,s.xxStateChange(1),null!=s.meshserver&&(t="*"+c+"meshrelay.ashx?p="+s.protocol+"&nodeid="+e+"&id="+s.tunnelid,null!=a&&""!=a&&(t+="&rauth="+a),s.meshserver.send({action:"msg",type:"tunnel",nodeid:s.nodeid,value:t,usage:s.protocol}))},s.xxOnSocketConnected=function(){1==s.debugmode&&console.log("onSocketConnected"),s.xxStateChange(2)},s.xxOnControlCommand=function(e){var t;try{t=JSON.parse(e)}catch(e){return}"102938"!=t.ctrlChannel?s.m.ProcessData?s.m.ProcessData(e):console.log(e):("undefined"!=typeof args&&args.redirtrace&&console.log("RedirRecv",t),"console"==t.type?s.setConsoleMessage(t.msg,t.msgid,t.msgargs,t.timeout):"metadata"==t.type?(s.metadata=t,s.onMetadataChange&&s.onMetadataChange(s.metadata)):"rtt"==t.type&&"number"==typeof t.time?(s.latency.current=(new Date).getTime()-t.time,null!=s.latency.callbacks&&s.latency.callback(s.latency.current)):null!=s.webrtc?"answer"==t.type?s.webrtc.setRemoteDescription(new RTCSessionDescription(t),function(){},s.xxCloseWebRTC):"webrtc0"==t.type?(s.webSwitchOk=!0,l()):"webrtc1"==t.type?s.sendCtrlMsg('{"ctrlChannel":"102938","type":"webrtc2"}'):t.type:"ping"==t.type&&s.sendCtrlMsg('{"ctrlChannel":"102938","type":"pong"}'))},s.setConsoleMessage=function(e,t,n,o){s.consoleMessage!=e&&(s.consoleMessage=e,s.consoleMessageId=t,s.consoleMessageArgs=n,s.consoleMessageTimeout=o,s.onConsoleMessageChange)&&s.onConsoleMessageChange(s,s.consoleMessage,s.consoleMessageId)},s.sendCtrlMsg=function(e){if(1==s.ctrlMsgAllowed){"undefined"!=typeof args&&args.redirtrace&&console.log("RedirSend",typeof e,e);try{s.socket.send(e)}catch(e){}}},s.xxOnMessage=function(e){if(s.State<3&&("c"==e.data||"cr"==e.data)){if("cr"==e.data&&(s.serverIsRecording=!0),null!=s.options){delete s.options.action,s.options.type="options";try{s.sendCtrlMsg(JSON.stringify(s.options))}catch(e){}}try{s.socket.send(s.protocol)}catch(e){}s.xxStateChange(3),1==s.attemptWebRTC&&("undefined"!=typeof RTCPeerConnection?s.webrtc=new RTCPeerConnection(null):"undefined"!=typeof webkitRTCPeerConnection&&(s.webrtc=new webkitRTCPeerConnection(null)),null!=s.webrtc)&&s.webrtc.createDataChannel&&(s.webchannel=s.webrtc.createDataChannel("DataChannel",{}),s.webchannel.binaryType="arraybuffer",s.webchannel.onmessage=s.xxOnMessage,s.webchannel.onopen=function(){s.webRtcActive=!0,l()},s.webchannel.onclose=function(e){s.webRtcActive&&s.Stop()},s.webrtc.onicecandidate=function(e){if(null==e.candidate)try{s.sendCtrlMsg(JSON.stringify(s.webrtcoffer))}catch(e){}else s.webrtcoffer.sdp+="a="+e.candidate.candidate+"\r\n"},s.webrtc.oniceconnectionstatechange=function(){null!=s.webrtc&&("disconnected"==s.webrtc.iceConnectionState?1==s.webRtcActive?s.Stop():s.xxCloseWebRTC():"failed"==s.webrtc.iceConnectionState&&s.xxCloseWebRTC())},s.webrtc.createOffer(function(e){s.webrtcoffer=e,s.webrtc.setLocalDescription(e,function(){},s.xxCloseWebRTC)},s.xxCloseWebRTC,{mandatory:{OfferToReceiveAudio:!1,OfferToReceiveVideo:!1}}))}else if("string"==typeof e.data)"~"==e.data[0]?s.m.ProcessData(e.data):s.xxOnControlCommand(e.data);else if(s.m.ProcessBinaryCommand){if(!(0==u&&e.data.byteLength<4))if(0!=u){var t=new Uint8Array(e.data);if(g.push(t),u+=t.byteLength,d<=u){var n,o=new Uint8Array(u),a=0;for(n in g)o.set(g[n],a),a+=g[n].byteLength;s.m.ProcessBinaryCommand(i,d,o),u=d=i=0,g=[]}}else{var c=((t=new Uint8Array(e.data))[0]<<8)+t[1],r=(t[2]<<8)+t[3];27==c&&8==r&&(c=(t[8]<<8)+t[9],r=(t[5]<<16)+(t[6]<<8)+t[7],t=t.slice(8)),r!=t.byteLength?(i=c,d=r,u=t.byteLength,g=[t]):s.m.ProcessBinaryCommand(c,r,t)}}else s.m.ProcessBinaryData?s.m.ProcessBinaryData(new Uint8Array(e.data)):e.data.byteLength<16e3?s.m.ProcessData(String.fromCharCode.apply(null,new Uint8Array(e.data))):(c=new Blob([new Uint8Array(e.data)]),(r=new FileReader).onload=function(e){s.m.ProcessData(e.target.result)},r.readAsBinaryString(c))};var i=0,d=0,u=0,g=[];return s.sendText=function(e){"string"!=typeof e&&(e=JSON.stringify(e)),s.send(encode_utf8(e))},s.send=function(e){"undefined"!=typeof args&&args.redirtrace&&console.log("RedirSend",typeof e,e.length,"{"==e[0]?e:rstr2hex(e).substring(0,64));try{if(null!=s.socket&&s.socket.readyState==WebSocket.OPEN)if("string"==typeof e){if(1==s.debugmode)for(var t=new Uint8Array(e.length),n=[],o=0;o>8&248)+","+(c>>3&252)+","+((31&c)<<3))+")");var f=k(a);n=x(0,n),S.canvas.fillRect(a=f,n,r,o)}else if(1>d&p],u++)}else{for(d=0;d>d&p],u++)}w(S.spare,a,n)}else if(128==l){if(2==S.bpp)for(;u>8&248,S.spare.data[r+1]=e>>3&252,S.spare.data[r+2]=(31&e)<<3}function b(e,t,a){if(S.graymode){var n=t<<2;for(S.lowcolor&&(e<<=4);0<=--a;)S.spare.data[n]=S.spare.data[n+1]=S.spare.data[n+2]=e,n+=4}else for(var n=t<<2,r=224&e,o=(28&e)<<3,i=T((3&e)<<6);0<=--a;)S.spare.data[n]=r,S.spare.data[n+1]=o,S.spare.data[n+2]=i,n+=4}function D(e,t,a){for(var n=t<<2,r=e>>8&248,o=e>>3&252,i=(31&e)<<3;0<=--a;)S.spare.data[n]=r,S.spare.data[n+1]=o,S.spare.data[n+2]=i,n+=4}function k(e){return 0==S.rotation||1==S.rotation?e:2==S.rotation?e-S.canvas.canvas.width:3==S.rotation?e-S.canvas.canvas.height:0}function x(e,t){return 0==S.rotation?t:1==S.rotation?t-S.canvas.canvas.width:2==S.rotation?t-S.canvas.canvas.height:3==S.rotation?t:0}function T(e){return 127>32)+IntToStr(32&n)):(S.recordedSize+=a.length,ShortToStr(e)+ShortToStr(t)+IntToStr(a.length)+IntToStr(n>>32)+IntToStr(32&n)+a)}return S.GrabMouseInput=function(){var e;1!=n&&((e=S.canvas.canvas).onmouseup=S.mouseup,e.onmousedown=S.mousedown,e.onmousemove=S.mousemove,e.onwheel=S.mousewheel,n=!0)},S.UnGrabMouseInput=function(){var e;0!=n&&((e=S.canvas.canvas).onmousemove=null,e.onmouseup=null,e.onmousedown=null,e.onwheel=null,n=!1)},S.GrabKeyInput=function(){1!=o&&(document.onkeyup=S.handleKeyUp,document.onkeydown=S.handleKeyDown,document.onkeypress=S.handleKeys,o=!0)},S.UnGrabKeyInput=function(){0!=o&&(document.onkeyup=null,document.onkeydown=null,document.onkeypress=null,o=!1)},S.handleKeys=function(e){return S.haltEvent(e)},S.handleKeyUp=function(e){return a(0,e)},S.handleKeyDown=function(e){return a(1,e)},S.haltEvent=function(e){return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),!1},S.mousedblclick=function(e){},S.mousewheel=function(e){var t,a=0;if("number"==typeof e.deltaY?a=-1*e.deltaY:"number"==typeof e.detail?a=-1*e.detail:"number"==typeof e.wheelDelta&&(a=e.wheelDelta),0!=a)return S.ReverseMouseWheel&&(a*=-1),t=S.buttonmask,S.buttonmask|=1<<(0>8,255&S.width,S.height>>8,255&S.height)+S.DeskRecordServerInit.substring(4),S.recordedData.push(I(2,1,S.DeskRecordServerInit)),S.recordedData.push(I(3,0,atob(S.CanvasId.toDataURL("image/png").split(",")[1]))),!0)},S.StopRecording=function(){var e;if(null!=S.recordedData)return(e=S.recordedData).push(I(3,0,"MeshCentralMCREC")),delete S.recordedData,delete S.recordedStart,delete S.recordedSize,e},S} \ No newline at end of file +var CreateAmtRemoteDesktop=function(e,t){var S={};function g(e){return String.fromCharCode.apply(null,e)}function p(e,t,a,n,r,o,i){var s,c,h,d,l=e[t++],v={},u=0,m=0;if(0==l){if(2==S.bpp)for(d=0;d>8&248)+","+(c>>3&252)+","+((31&c)<<3))+")");var f=k(a);n=x(0,n),S.canvas.fillRect(a=f,n,r,o)}else if(1>d&p],u++)}else{for(d=0;d>d&p],u++)}w(S.spare,a,n)}else if(128==l){if(2==S.bpp)for(;u>8&248,S.spare.data[r+1]=e>>3&252,S.spare.data[r+2]=(31&e)<<3}function b(e,t,a){if(S.graymode){var n=t<<2;for(S.lowcolor&&(e<<=4);0<=--a;)S.spare.data[n]=S.spare.data[n+1]=S.spare.data[n+2]=e,n+=4}else for(var n=t<<2,r=224&e,o=(28&e)<<3,i=T((3&e)<<6);0<=--a;)S.spare.data[n]=r,S.spare.data[n+1]=o,S.spare.data[n+2]=i,n+=4}function D(e,t,a){for(var n=t<<2,r=e>>8&248,o=e>>3&252,i=(31&e)<<3;0<=--a;)S.spare.data[n]=r,S.spare.data[n+1]=o,S.spare.data[n+2]=i,n+=4}function k(e){return 0==S.rotation||1==S.rotation?e:2==S.rotation?e-S.canvas.canvas.width:3==S.rotation?e-S.canvas.canvas.height:0}function x(e,t){return 0==S.rotation?t:1==S.rotation?t-S.canvas.canvas.width:2==S.rotation?t-S.canvas.canvas.height:3==S.rotation?t:0}function T(e){return 127{if(e.byteLength<8)return 0;if(t=t.getUint32(4)+8,e.byteLength{for(var t=new Uint8Array(e.length),a=0,n=e.length;a>32)+IntToStr(32&n)):(S.recordedSize+=a.length,ShortToStr(e)+ShortToStr(t)+IntToStr(a.length)+IntToStr(n>>32)+IntToStr(32&n)+a)}return S.GrabMouseInput=function(){var e;1!=n&&((e=S.canvas.canvas).onmouseup=S.mouseup,e.onmousedown=S.mousedown,e.onmousemove=S.mousemove,e.onwheel=S.mousewheel,n=!0)},S.UnGrabMouseInput=function(){var e;0!=n&&((e=S.canvas.canvas).onmousemove=null,e.onmouseup=null,e.onmousedown=null,e.onwheel=null,n=!1)},S.GrabKeyInput=function(){1!=o&&(document.onkeyup=S.handleKeyUp,document.onkeydown=S.handleKeyDown,document.onkeypress=S.handleKeys,o=!0)},S.UnGrabKeyInput=function(){0!=o&&(document.onkeyup=null,document.onkeydown=null,document.onkeypress=null,o=!1)},S.handleKeys=function(e){return S.haltEvent(e)},S.handleKeyUp=function(e){return a(0,e)},S.handleKeyDown=function(e){return a(1,e)},S.haltEvent=function(e){return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),!1},S.mousedblclick=function(e){},S.mousewheel=function(e){var t,a=0;if("number"==typeof e.deltaY?a=-1*e.deltaY:"number"==typeof e.detail?a=-1*e.detail:"number"==typeof e.wheelDelta&&(a=e.wheelDelta),0!=a)return S.ReverseMouseWheel&&(a*=-1),t=S.buttonmask,S.buttonmask|=1<<(0>8,255&S.width,S.height>>8,255&S.height)+S.DeskRecordServerInit.substring(4),S.recordedData.push(I(2,1,S.DeskRecordServerInit)),S.recordedData.push(I(3,0,atob(S.CanvasId.toDataURL("image/png").split(",")[1]))),!0)},S.StopRecording=function(){var e;if(null!=S.recordedData)return(e=S.recordedData).push(I(3,0,"MeshCentralMCREC")),delete S.recordedData,delete S.recordedStart,delete S.recordedSize,e},S} \ No newline at end of file diff --git a/public/scripts/amt-ider-ws-0.0.1-min.js b/public/scripts/amt-ider-ws-0.0.1-min.js index 9abe7730..9a4b6f5b 100644 --- a/public/scripts/amt-ider-ws-0.0.1-min.js +++ b/public/scripts/amt-ider-ws-0.0.1-min.js @@ -1 +1 @@ -var CreateAmtRemoteIder=function(){var m={};function l(){urlvars&&urlvars.idertrace&&console.log(...arguments)}m.protocol=3,m.bytesToAmt=0,m.bytesFromAmt=0,m.rx_timeout=3e4,m.tx_timeout=0,m.heartbeat=2e4,m.version=1,m.acc="",m.inSequence=0,m.outSequence=0,m.iderinfo=null,m.enabled=!1,m.iderStart=0,m.floppy=null,m.cdrom=null,m.floppyReady=!1,m.cdromReady=!1,m.pingTimer=null;var f=String.fromCharCode(0,38,49,128,0,0,0,0,5,30,16,169,8,32,2,0,3,195,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0),u=String.fromCharCode(0,92,36,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0,3,22,0,160,0,0,0,0,0,18,2,0,0,0,0,0,0,0,160,0,0,0,5,30,16,169,8,32,2,0,3,195,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0,8,10,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,17,36,49),h=String.fromCharCode(0,38,36,128,0,0,0,0,5,30,4,176,2,18,2,0,0,80,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0),p=String.fromCharCode(0,92,36,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0,3,22,0,160,0,0,0,0,0,18,2,0,0,0,0,0,0,0,160,0,0,0,5,30,4,176,2,18,2,0,0,80,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0,8,10,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,17,36,49),R=String.fromCharCode(0,18,1,128,0,0,0,0,26,10,0,0,0,0,0,0,0,0,0,0),E=String.fromCharCode(0,18,1,128,0,0,0,0,29,10,0,0,0,0,0,0,0,0,0,0),I=String.fromCharCode(0,32,1,128,0,0,0,0,42,24,0,0,0,0,32,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0),g=String.fromCharCode(0,40,1,128,0,0,0,0,1,6,0,255,0,0,0,0,42,24,0,0,0,0,2,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0),b=(String.fromCharCode(0,0,0,40,0,0,0,8),String.fromCharCode(0,0,3,4,0,8,1,0)),A=String.fromCharCode(0,1,3,4,0,0,0,2),T=String.fromCharCode(0,2,3,4,0,0,0,0),D=String.fromCharCode(0,3,3,4,41,0,0,2),y=String.fromCharCode(0,16,1,8,0,0,8,0,0,1,0,0),_=String.fromCharCode(0,30,3,0),k=String.fromCharCode(1,0,3,0),v=String.fromCharCode(1,5,3,0),O=String.fromCharCode(0,18,36,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0),X=String.fromCharCode(0,18,49,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0),w=String.fromCharCode(0,14,1,128,0,0,0,0,1,6,0,255,0,0,0,0);function F(e,r,n,a){var o=null,t=0;160==e&&(o=m.floppy,null!=m.floppy)&&(t=m.floppy.size>>9),176==e&&(o=m.cdrom,null!=m.cdrom)&&(t=m.cdrom.size>>11),n<0||tm.iderinfo.readbfr&&(n=m.iderinfo.readbfr);c-=n;S+=n;var o=new FileReader;o.onload=function(){m.SendDataToHost(d,0==c,this.result,1&r),0>8,0,a?180:181,0,2,0,255&o,o>>8,e,88,133,0,3,0,0,0,e,80,0,0,0,0,0,0)+n,r,a):m.SendCommand(84,String.fromCharCode(0,255&n.length,n.length>>8,0,a?180:181,0,2,0,255&o,o>>8,e,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0)+n,r,a)},m.SendGetDataFromHost=function(e,r){m.SendCommand(82,String.fromCharCode(0,255&r,r>>8,0,181,0,0,0,255&r,r>>8,e,88,0,0,0,0,0,0,0,0,0,0,0),!1)},m.SendDisableEnableFeatures=function(e,r){null==r&&(r=""),m.SendCommand(72,String.fromCharCode(e)+r)};var d,S,c,C=!(m.ProcessDataEx=function(){if(!(m.acc.length<8))switch(m.acc.charCodeAt(0)){case 65:return m.acc.length<30?0:(t=m.acc.charCodeAt(29),m.acc.length<30+t?0:(m.iderinfo={},m.iderinfo.major=m.acc.charCodeAt(8),m.iderinfo.minor=m.acc.charCodeAt(9),m.iderinfo.fwmajor=m.acc.charCodeAt(10),m.iderinfo.fwminor=m.acc.charCodeAt(11),m.iderinfo.readbfr=ReadShortX(m.acc,16),m.iderinfo.writebfr=ReadShortX(m.acc,18),m.iderinfo.proto=m.acc.charCodeAt(21),m.iderinfo.iana=ReadIntX(m.acc,25),l(m.iderinfo),0!=m.iderinfo.proto&&(l("Unknown proto",m.iderinfo.proto),m.Stop()),8192>9)-1:S);break;case 176:if(null==m.floppy||0==m.floppy.size)return m.SendCommandEndResponse(0,2,e,58,0);l("DEV_CDDVD",S=null!=m.cdrom?(m.cdrom.size>>11)-1:S);break;default:return l("SCSI Internal error 4",e)}l("SCSI: READ_CAPACITY2",e,a),m.SendDataToHost(a,!0,IntToStr(S)+String.fromCharCode(0,0,176==e?8:2,0),1&n);break;case 40:c=ReadInt(r,2),S=ReadShort(r,7),l("SCSI: READ_10",e,c,S),F(e,c,S,n);break;case 42:case 46:c=ReadInt(r,2),S=ReadShort(r,7),l("SCSI: WRITE_10",e,c,S),m.SendGetDataFromHost(e,512*S);break;case 67:var d=ReadShort(r,7),c=2&r.charCodeAt(1),C=7&r.charCodeAt(2);switch(0==C&&(C=r.charCodeAt(9)>>6),l("SCSI: READ_TOC, dev="+e+", buflen="+d+", msf="+c+", format="+C),e){case 160:return m.SendCommandEndResponse(1,5,e,32,0);case 176:break;default:return l("SCSI Internal error 9",e)}1==C?m.SendDataToHost(e,!0,String.fromCharCode(0,10,1,1,0,20,1,0,0,0,0,0),1&n):0==C&&(c?m.SendDataToHost(e,!0,String.fromCharCode(0,18,1,1,0,20,1,0,0,0,2,0,0,20,170,0,0,0,52,19),1&n):m.SendDataToHost(e,!0,String.fromCharCode(0,18,1,1,0,20,1,0,0,0,0,0,0,20,170,0,0,0,0,0),1&n));break;case 70:C=2!=r.charCodeAt(1),c=ReadShort(r,2),d=ReadShort(r,7);return l("SCSI: GET_CONFIGURATION",e,C,c,d),0==d?m.SendDataToHost(e,!0,IntToStr(60)+IntToStr(8),1&n):(s=IntToStr(8),0==c&&(s+=b),(1==c||C&&c<1)&&(s+=A),(2==c||C&&c<2)&&(s+=T),(3==c||C&&c<3)&&(s+=D),(16==c||C&&c<16)&&(s+=y),(30==c||C&&c<30)&&(s+=_),(256==c||C&&c<256)&&(s+=k),(261==c||C&&c<261)&&(s+=v),(s=IntToStr(s.length)+s).length>d&&(s=s.substring(0,d)),m.SendDataToHost(e,!0,s,1&n));case 74:l("SCSI: GET_EVENT_STATUS_NOTIFICATION",e,r.charCodeAt(1),r.charCodeAt(4),r.charCodeAt(9)),1!=r.charCodeAt(1)&&16!=r.charCodeAt(4)?(l("SCSI ERROR"),m.SendCommandEndResponse(1,5,e,38,1)):(C=0,(160==e&&null!=m.floppy||176==e&&null!=m.cdrom)&&(C=2),m.SendDataToHost(e,!0,String.fromCharCode(0,C,128,0),1&n));break;case 76:m.SendCommand(81,IntToStrX(0)+IntToStrX(0)+IntToStrX(0)+String.fromCharCode(135,80,3,0,0,0,176,81,5,32,0),!0);break;case 81:return l("SCSI READ_DISC_INFO",e),m.SendCommandEndResponse(0,5,e,32,0);case 85:return l("SCSI ERROR: MODE_SELECT_10",e),m.SendCommandEndResponse(1,5,e,32,0);case 90:l("SCSI: MODE_SENSE_10",e,63&r.charCodeAt(2));var d=ReadShort(r,7),s=null;if(0==d)return m.SendDataToHost(e,!0,IntToStr(60)+IntToStr(8),1&n);var i=0;switch(160==e?null!=m.floppy&&(i=m.floppy.size>>9):null!=m.cdrom&&(i=m.cdrom.size>>11),63&r.charCodeAt(2)){case 1:s=160==e?i<=2880?O:X:w;break;case 5:160==e&&(s=i<=2880?h:f);break;case 63:s=160==e?i<=2880?p:u:g;break;case 26:176==e&&(s=R);break;case 29:176==e&&(s=E);break;case 42:176==e&&(s=I)}null==s?m.SendCommandEndResponse(0,5,e,32,0):m.SendDataToHost(e,!0,s,1&n);break;default:return l("IDER: Unknown SCSI command",r.charCodeAt(0)),m.SendCommandEndResponse(0,5,e,32,0)}}(e,a,o,n),28);case 83:var t;return m.acc.length<14?0:(t=ReadShortX(m.acc,9),m.acc.length<14+t?0:(l("SCSI_WRITE, len = "+(14+t)),m.SendCommand(81,String.fromCharCode(0,0,0,0,0,0,0,0,0,0,0,0,135,112,3,0,0,0,160,81,7,39,0),!0),14+t));default:l("Unknown IDER command",m.acc[0]),m.Stop()}return 0}),s=null;return m} \ No newline at end of file +var CreateAmtRemoteIder=function(){var m={};function l(){urlvars&&urlvars.idertrace&&console.log(...arguments)}m.protocol=3,m.bytesToAmt=0,m.bytesFromAmt=0,m.rx_timeout=3e4,m.tx_timeout=0,m.heartbeat=2e4,m.version=1,m.acc="",m.inSequence=0,m.outSequence=0,m.iderinfo=null,m.enabled=!1,m.iderStart=0,m.floppy=null,m.cdrom=null,m.floppyReady=!1,m.cdromReady=!1,m.pingTimer=null;var f=String.fromCharCode(0,38,49,128,0,0,0,0,5,30,16,169,8,32,2,0,3,195,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0),u=String.fromCharCode(0,92,36,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0,3,22,0,160,0,0,0,0,0,18,2,0,0,0,0,0,0,0,160,0,0,0,5,30,16,169,8,32,2,0,3,195,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0,8,10,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,17,36,49),h=String.fromCharCode(0,38,36,128,0,0,0,0,5,30,4,176,2,18,2,0,0,80,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0),p=String.fromCharCode(0,92,36,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0,3,22,0,160,0,0,0,0,0,18,2,0,0,0,0,0,0,0,160,0,0,0,5,30,4,176,2,18,2,0,0,80,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,2,208,0,0,8,10,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,17,36,49),R=String.fromCharCode(0,18,1,128,0,0,0,0,26,10,0,0,0,0,0,0,0,0,0,0),E=String.fromCharCode(0,18,1,128,0,0,0,0,29,10,0,0,0,0,0,0,0,0,0,0),I=String.fromCharCode(0,32,1,128,0,0,0,0,42,24,0,0,0,0,32,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0),g=String.fromCharCode(0,40,1,128,0,0,0,0,1,6,0,255,0,0,0,0,42,24,0,0,0,0,2,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0),b=(String.fromCharCode(0,0,0,40,0,0,0,8),String.fromCharCode(0,0,3,4,0,8,1,0)),A=String.fromCharCode(0,1,3,4,0,0,0,2),T=String.fromCharCode(0,2,3,4,0,0,0,0),D=String.fromCharCode(0,3,3,4,41,0,0,2),y=String.fromCharCode(0,16,1,8,0,0,8,0,0,1,0,0),_=String.fromCharCode(0,30,3,0),k=String.fromCharCode(1,0,3,0),v=String.fromCharCode(1,5,3,0),O=String.fromCharCode(0,18,36,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0),X=String.fromCharCode(0,18,49,128,0,0,0,0,1,10,0,1,0,0,0,0,2,0,0,0),w=String.fromCharCode(0,14,1,128,0,0,0,0,1,6,0,255,0,0,0,0);function F(e,r,n,a){var o=null,t=0;160==e&&(o=m.floppy,null!=m.floppy)&&(t=m.floppy.size>>9),176==e&&(o=m.cdrom,null!=m.cdrom)&&(t=m.cdrom.size>>11),n<0||tm.iderinfo.readbfr&&(n=m.iderinfo.readbfr);c-=n;S+=n;var o=new FileReader;o.onload=function(){m.SendDataToHost(d,0==c,this.result,1&r),0>8,0,a?180:181,0,2,0,255&o,o>>8,e,88,133,0,3,0,0,0,e,80,0,0,0,0,0,0)+n,r,a):m.SendCommand(84,String.fromCharCode(0,255&n.length,n.length>>8,0,a?180:181,0,2,0,255&o,o>>8,e,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0)+n,r,a)},m.SendGetDataFromHost=function(e,r){m.SendCommand(82,String.fromCharCode(0,255&r,r>>8,0,181,0,0,0,255&r,r>>8,e,88,0,0,0,0,0,0,0,0,0,0,0),!1)},m.SendDisableEnableFeatures=function(e,r){null==r&&(r=""),m.SendCommand(72,String.fromCharCode(e)+r)};var d,S,c,C=!(m.ProcessDataEx=function(){if(!(m.acc.length<8))switch(m.acc.charCodeAt(0)){case 65:return m.acc.length<30?0:(t=m.acc.charCodeAt(29),m.acc.length<30+t?0:(m.iderinfo={},m.iderinfo.major=m.acc.charCodeAt(8),m.iderinfo.minor=m.acc.charCodeAt(9),m.iderinfo.fwmajor=m.acc.charCodeAt(10),m.iderinfo.fwminor=m.acc.charCodeAt(11),m.iderinfo.readbfr=ReadShortX(m.acc,16),m.iderinfo.writebfr=ReadShortX(m.acc,18),m.iderinfo.proto=m.acc.charCodeAt(21),m.iderinfo.iana=ReadIntX(m.acc,25),l(m.iderinfo),0!=m.iderinfo.proto&&(l("Unknown proto",m.iderinfo.proto),m.Stop()),8192{switch(r.charCodeAt(0)){case 0:switch(l("SCSI: TEST_UNIT_READY",e),e){case 160:if(null==m.floppy)return m.SendCommandEndResponse(1,2,e,58,0);if(0==m.floppyReady)return m.floppyReady=!0,m.SendCommandEndResponse(1,6,e,40,0);break;case 176:if(null==m.cdrom)return m.SendCommandEndResponse(1,2,e,58,0);if(0==m.cdromReady)return m.cdromReady=!0,m.SendCommandEndResponse(1,6,e,40,0);break;default:return l("SCSI Internal error 3",e)}m.SendCommandEndResponse(1,0,e,0,0);break;case 8:c=((31&r.charCodeAt(1))<<16)+(r.charCodeAt(2)<<8)+r.charCodeAt(3),S=r.charCodeAt(4),l("SCSI: READ_6",e,c,S=0==S?256:S),F(e,c,S,n);break;case 10:return c=((31&r.charCodeAt(1))<<16)+(r.charCodeAt(2)<<8)+r.charCodeAt(3),S=r.charCodeAt(4),l("SCSI: WRITE_6",e,c,S=0==S?256:S),m.SendCommandEndResponse(1,2,e,58,0);case 26:if(l("SCSI: MODE_SENSE_6",e),63==r.charCodeAt(2)&&0==r.charCodeAt(3)){var o=0,t=0;switch(e){case 160:if(null==m.floppy)return m.SendCommandEndResponse(1,2,e,58,0);o=0,t=128;break;case 176:if(null==m.cdrom)return m.SendCommandEndResponse(1,2,e,58,0);o=5,t=128;break;default:return l("SCSI Internal error 6",e)}return m.SendDataToHost(e,!0,String.fromCharCode(0,o,t,0),1&n)}m.SendCommandEndResponse(1,5,e,36,0);break;case 27:m.SendCommandEndResponse(1,0,e);break;case 30:if(l("SCSI: ALLOW_MEDIUM_REMOVAL",e),160==e&&null==m.floppy)return m.SendCommandEndResponse(1,2,e,58,0);if(176==e&&null==m.cdrom)return m.SendCommandEndResponse(1,2,e,58,0);m.SendCommandEndResponse(1,0,e,0,0);break;case 35:l("SCSI: READ_FORMAT_CAPACITIES",e);var d=ReadShort(r,7);switch(e){case 160:if(null==m.floppy||0==m.floppy.size)return m.SendCommandEndResponse(0,5,e,36,0);m.floppy.size;break;case 176:if(null==m.cdrom||0==m.cdrom.size)return m.SendCommandEndResponse(0,5,e,36,0);m.cdrom.size;break;default:return l("SCSI Internal error 4",e)}m.SendDataToHost(e,!0,IntToStr(8)+String.fromCharCode(0,0,11,64,2,0,2,0),1&n);break;case 37:l("SCSI: READ_CAPACITY",e);var S=0;switch(e){case 160:if(null==m.floppy||0==m.floppy.size)return m.SendCommandEndResponse(0,2,e,58,0);l("DEV_FLOPPY",S=null!=m.floppy?(m.floppy.size>>9)-1:S);break;case 176:if(null==m.floppy||0==m.floppy.size)return m.SendCommandEndResponse(0,2,e,58,0);l("DEV_CDDVD",S=null!=m.cdrom?(m.cdrom.size>>11)-1:S);break;default:return l("SCSI Internal error 4",e)}l("SCSI: READ_CAPACITY2",e,a),m.SendDataToHost(a,!0,IntToStr(S)+String.fromCharCode(0,0,176==e?8:2,0),1&n);break;case 40:c=ReadInt(r,2),S=ReadShort(r,7),l("SCSI: READ_10",e,c,S),F(e,c,S,n);break;case 42:case 46:c=ReadInt(r,2),S=ReadShort(r,7),l("SCSI: WRITE_10",e,c,S),m.SendGetDataFromHost(e,512*S);break;case 67:var d=ReadShort(r,7),c=2&r.charCodeAt(1),C=7&r.charCodeAt(2);switch(0==C&&(C=r.charCodeAt(9)>>6),l("SCSI: READ_TOC, dev="+e+", buflen="+d+", msf="+c+", format="+C),e){case 160:return m.SendCommandEndResponse(1,5,e,32,0);case 176:break;default:return l("SCSI Internal error 9",e)}1==C?m.SendDataToHost(e,!0,String.fromCharCode(0,10,1,1,0,20,1,0,0,0,0,0),1&n):0==C&&(c?m.SendDataToHost(e,!0,String.fromCharCode(0,18,1,1,0,20,1,0,0,0,2,0,0,20,170,0,0,0,52,19),1&n):m.SendDataToHost(e,!0,String.fromCharCode(0,18,1,1,0,20,1,0,0,0,0,0,0,20,170,0,0,0,0,0),1&n));break;case 70:C=2!=r.charCodeAt(1),c=ReadShort(r,2),d=ReadShort(r,7);return l("SCSI: GET_CONFIGURATION",e,C,c,d),0==d?m.SendDataToHost(e,!0,IntToStr(60)+IntToStr(8),1&n):(s=IntToStr(8),0==c&&(s+=b),(1==c||C&&c<1)&&(s+=A),(2==c||C&&c<2)&&(s+=T),(3==c||C&&c<3)&&(s+=D),(16==c||C&&c<16)&&(s+=y),(30==c||C&&c<30)&&(s+=_),(256==c||C&&c<256)&&(s+=k),(261==c||C&&c<261)&&(s+=v),(s=IntToStr(s.length)+s).length>d&&(s=s.substring(0,d)),m.SendDataToHost(e,!0,s,1&n));case 74:l("SCSI: GET_EVENT_STATUS_NOTIFICATION",e,r.charCodeAt(1),r.charCodeAt(4),r.charCodeAt(9)),1!=r.charCodeAt(1)&&16!=r.charCodeAt(4)?(l("SCSI ERROR"),m.SendCommandEndResponse(1,5,e,38,1)):(C=0,(160==e&&null!=m.floppy||176==e&&null!=m.cdrom)&&(C=2),m.SendDataToHost(e,!0,String.fromCharCode(0,C,128,0),1&n));break;case 76:m.SendCommand(81,IntToStrX(0)+IntToStrX(0)+IntToStrX(0)+String.fromCharCode(135,80,3,0,0,0,176,81,5,32,0),!0);break;case 81:return l("SCSI READ_DISC_INFO",e),m.SendCommandEndResponse(0,5,e,32,0);case 85:return l("SCSI ERROR: MODE_SELECT_10",e),m.SendCommandEndResponse(1,5,e,32,0);case 90:l("SCSI: MODE_SENSE_10",e,63&r.charCodeAt(2));var d=ReadShort(r,7),s=null;if(0==d)return m.SendDataToHost(e,!0,IntToStr(60)+IntToStr(8),1&n);var i=0;switch(160==e?null!=m.floppy&&(i=m.floppy.size>>9):null!=m.cdrom&&(i=m.cdrom.size>>11),63&r.charCodeAt(2)){case 1:s=160==e?i<=2880?O:X:w;break;case 5:160==e&&(s=i<=2880?h:f);break;case 63:s=160==e?i<=2880?p:u:g;break;case 26:176==e&&(s=R);break;case 29:176==e&&(s=E);break;case 42:176==e&&(s=I)}null==s?m.SendCommandEndResponse(0,5,e,32,0):m.SendDataToHost(e,!0,s,1&n);break;default:return l("IDER: Unknown SCSI command",r.charCodeAt(0)),m.SendCommandEndResponse(0,5,e,32,0)}})(e,a,o,n),28);case 83:var t;return m.acc.length<14?0:(t=ReadShortX(m.acc,9),m.acc.length<14+t?0:(l("SCSI_WRITE, len = "+(14+t)),m.SendCommand(81,String.fromCharCode(0,0,0,0,0,0,0,0,0,0,0,0,135,112,3,0,0,0,160,81,7,39,0),!0),14+t));default:l("Unknown IDER command",m.acc[0]),m.Stop()}return 0}),s=null;return m} \ No newline at end of file diff --git a/public/scripts/amt-redir-ws-0.1.0-min.js b/public/scripts/amt-redir-ws-0.1.0-min.js index f13b0515..dec65dbf 100644 --- a/public/scripts/amt-redir-ws-0.1.0-min.js +++ b/public/scripts/amt-redir-ws-0.1.0-min.js @@ -1 +1 @@ -var CreateAmtRedirect=function(e,o){var y={};function x(e){return String.fromCharCode.apply(null,e)}return((y.m=e).parent=y).authCookie=o,y.State=0,y.socket=null,y.host=null,y.port=0,y.user=null,y.pass=null,y.authuri="/RedirectionService",y.tlsv1only=0,y.inDataCount=0,y.connectstate=0,y.protocol=e.protocol,y.acc=null,y.amtsequence=1,y.amtkeepalivetimer=null,y.onStateChanged=null,y.Start=function(e,t,n,r,a){y.host=e,y.port=t,y.user=n,y.pass=r,y.connectstate=0,y.inDataCount=0;e=window.location.protocol.replace("http","ws")+"//"+window.location.host+window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/"))+"/webrelay.ashx?p=2&host="+e+"&port="+t+"&tls="+a+("*"==n?"&serverauth=1":"")+(void 0===r?"&serverauth=1&user="+n:"");null!=o&&""!=o&&(e+="&auth="+o),y.socket=new WebSocket(e),y.socket.binaryType="arraybuffer",y.socket.onopen=y.xxOnSocketConnected,y.socket.onmessage=y.xxOnMessage,y.socket.onclose=y.xxOnSocketClosed,y.xxStateChange(1)},y.xxOnSocketConnected=function(){y.xxStateChange(2),1==y.protocol&&y.directSend(new Uint8Array([16,0,0,0,83,79,76,32])),2==y.protocol&&y.directSend(new Uint8Array([16,1,0,0,75,86,77,82])),3==y.protocol&&y.directSend(new Uint8Array([16,0,0,0,73,68,69,82]))},y.xxOnMessage=function(e){if(e.data&&-1!=y.connectstate){if(y.inDataCount++,1==y.connectstate&&(2==y.protocol||3==y.protocol))return y.m.ProcessBinaryData?y.m.ProcessBinaryData(e.data):y.m.ProcessData(x(e.data));var t;for(null==y.acc?y.acc=e.data:((t=new Uint8Array(y.acc.byteLength+e.data.byteLength)).set(new Uint8Array(y.acc),0),t.set(new Uint8Array(e.data),y.acc.byteLength),y.acc=t.buffer);null!=y.acc&&1<=y.acc.byteLength;){var n=0,r=new Uint8Array(y.acc);switch(r[0]){case 17:if(r.byteLength<4)return;var a=r[1];if(0===a){if(r.byteLength<13)return;a=r[12];if(r.byteLength<13+a)return;y.directSend(new Uint8Array([19,0,0,0,0,0,0,0,0])),n=13+a}else y.Stop(1);break;case 20:if(r.byteLength<9)return;var o=new DataView(y.acc).getUint32(5,!0);if(r.byteLength<9+o)return;var a=r[1],c=r[4],s=[];for(i=0;i{for(var t="",n=0;nAmtSetupBinSetupGuids.length)return null;for(var r,t=[],o=AmtSetupBinSetupGuids[e.fileType-1],a=0,o=(o=(o=(o=(o=(o=(o=(o+=ShortToStrX(e.recordChunkCount))+ShortToStrX(e.recordHeaderByteCount))+IntToStrX(e.recordNumber))+String.fromCharCode(e.majorVersion,e.minorVersion))+ShortToStrX(e.flags))+IntToStrX(e.records.length))+IntToStrX(e.dataRecordsConsumed))+ShortToStrX(e.dataRecordChunkCount);o.length<512;)o+="\0";for(r in t.push(o),e.records){var n,i="",d=e.records[r],i=(i=(i=(i=(i=(i=(i+=IntToStrX(d.typeIdentifier))+IntToStrX(d.flags))+IntToStrX(0))+IntToStrX(0))+ShortToStrX(1))+ShortToStrX(24))+IntToStrX(++a);for(n in d.variables.sort(AmtSetupBinVariableCompare),d.variables){var u="",s=d.variables[n],l=s.value;for(s.type=AmtSetupBinVarIds[s.moduleid][s.varid][0],0r.moduleid?1:e.moduleidr.varid?1:e.varidAmtSetupBinSetupGuids.length)return null;for(var r,t=[],o=AmtSetupBinSetupGuids[e.fileType-1],a=0,o=(o=(o=(o=(o=(o=(o=(o+=ShortToStrX(e.recordChunkCount))+ShortToStrX(e.recordHeaderByteCount))+IntToStrX(e.recordNumber))+String.fromCharCode(e.majorVersion,e.minorVersion))+ShortToStrX(e.flags))+IntToStrX(e.records.length))+IntToStrX(e.dataRecordsConsumed))+ShortToStrX(e.dataRecordChunkCount);o.length<512;)o+="\0";for(r in t.push(o),e.records){var n,i="",d=e.records[r],i=(i=(i=(i=(i=(i=(i+=IntToStrX(d.typeIdentifier))+IntToStrX(d.flags))+IntToStrX(0))+IntToStrX(0))+ShortToStrX(1))+ShortToStrX(24))+IntToStrX(++a);for(n in d.variables.sort(AmtSetupBinVariableCompare),d.variables){var u="",s=d.variables[n],l=s.value;for(s.type=AmtSetupBinVarIds[s.moduleid][s.varid][0],0r.moduleid?1:e.moduleid":D=!1,d=0;break;case"7":c=S,s=T,d=0;break;case"8":S=c,T=s,d=0;break;case"M":for(var h=l[1];h>=l[0]+1;h--)for(var a=0;al[0]-1;h--)for(a=0;am.height)&&(T=m.height);break;case"C":1==t&&(0==r[0]?S++:S+=r[0],S>m.width)&&(S=m.width);break;case"D":1==t&&(0==r[0]?S--:S-=r[0],S<0)&&(S=0);break;case"d":1==t&&(T=(T=r[0]-1)>m.height?m.height:T)<0&&(T=0);break;case"G":1==t&&(S=(S=r[0]-1)<0?0:S)>m.width-1&&(S=m.width-1);break;case"P":var a=1;for(1==t&&(a=r[0]),n=S;nm.height&&(r[0]=m.height),r[1]>m.width&&(r[1]=m.width),T=r[0]-1,r[1]-1):T=0;break;case"m":for(n=0;nm.height-1&&(l[0]=m.height-1),l[1]<0&&(l[1]=0),l[1]>m.height-1&&(l[1]=m.height-1),l[0]>l[1]&&(l[0]=l[1]);break;case"S":a=1;1==t&&(a=r[0]);for(var c=l[0];c<=l[1]-a;c++)for(var f=0;fl[0]+a;c--)for(f=0;fl[0];c--)for(f=0;f=m.width&&(s=0,d++);break;default:console.log("Unknown terminal code",e,r,i)}}}(i,b,k+1,v),d=0);break;case 4:case 5:d=0;break;case 6:var o=i.charCodeAt(0);";"==i?k++:7==o?(function(e){var r;0!=e.length&&(0==(r=parseInt(e[0]))||2==r)&&1m.width&&(S=m.width),T>m.height-1&&(T=m.height-1),e){case"\b":0l[1]&&(m.recordLineTobackBuffer(0),x(1),T=l[1]),m.lineFeed="\r",S=0;break;case"\r":S=0;break;default:S>=m.width&&(S=0,C&&T++,T>=m.height-1)&&(x(1),T=m.height-1),o(e),S++}}}function o(e){y[T][S]=e,p[T][S]=(u<<6)+(w<<12)+g}function L(){for(var e=(u<<6)+(w<<12)+g,r=S;r")},m.TermDrawLine=function(e,r,t){for(var i,n,h,a,o=1,c=0;c>a&63],1&i&&(e+=";text-decoration:underline"),e+=';">',t=""+(t=""),o=i),n=y[r][c]){case"&":e+="&";break;case"<":e+="<";break;case">":e+=">";break;case" ":e+=" ";break;default:e+=n}return[e,t]},m.TermDraw=function(){for(var e="",r="",t=0;t")}var n=(B=800"+n+r+e+"",m.DivElement.scrollTop=m.DivElement.scrollHeight,0==m.heightLock&&setTimeout(m.TermLockHeight,10)},m.TermLockHeight=function(){m.heightLock=m.DivElement.clientHeight,m.DivElement.style.height=m.DivElement.parentNode.style.height=m.heightLock+"px",m.DivElement.style["overflow-y"]="scroll"},m.TermInit=function(){m.TermResetScreen()},m.heightLock=0,m.DivElement.style.height="",null!=r&&null!=r.cols&&null!=r.rows?m.Init(r.cols,r.rows):m.Init(),m} \ No newline at end of file +var CreateAmtRemoteTerminal=function(e,r){var l,m={},f=(m.DivId=e,m.DivElement=document.getElementById(e),m.protocol=1,r.protocol&&(m.protocol=r.protocol),m.terminalEmulation=1,m.fxEmulation=0,m.lineFeed="\r\n",m.debugmode=0,m.width=80,m.height=25,m.heightLock=0,["000000","BB0000","00BB00","BBBB00","0000BB","BB00BB","00BBBB","BBBBBB","555555","FF5555","55FF55","FFFF55","5555FF","FF55FF","55FFFF","FFFFFF"]),g=0,w=7,u=0,C=!0,S=0,T=0,c=0,s=0,d=0,b=[],k=0,v=0,p=[],y=[],n=!1,K=!0,D=!1,B=[],F="";m.title=null,m.onTitleChange=null,m.Start=function(){},m.Init=function(e,r){m.width=e||80,m.height=r||25;for(var t=0;t":D=!1,d=0;break;case"7":c=S,s=T,d=0;break;case"8":S=c,T=s,d=0;break;case"M":for(var h=l[1];h>=l[0]+1;h--)for(var a=0;al[0]-1;h--)for(a=0;a{if(1==i)switch(e){case"l":25==r[0]&&(K=!1);break;case"h":25==r[0]&&(K=!0)}else if(0==i){var n,h;switch(e){case"c":m.TermResetScreen();break;case"A":1==t&&(0==r[0]?T--:T-=r[0],T<0)&&(T=0);break;case"B":1==t&&(0==r[0]?T++:T+=r[0],T>m.height)&&(T=m.height);break;case"C":1==t&&(0==r[0]?S++:S+=r[0],S>m.width)&&(S=m.width);break;case"D":1==t&&(0==r[0]?S--:S-=r[0],S<0)&&(S=0);break;case"d":1==t&&(T=(T=r[0]-1)>m.height?m.height:T)<0&&(T=0);break;case"G":1==t&&(S=(S=r[0]-1)<0?0:S)>m.width-1&&(S=m.width-1);break;case"P":var a=1;for(1==t&&(a=r[0]),n=S;nm.height&&(r[0]=m.height),r[1]>m.width&&(r[1]=m.width),T=r[0]-1,r[1]-1):T=0;break;case"m":for(n=0;n{for(var e=(w<<6)+(u<<12)+g,r=0;rm.height-1&&(l[0]=m.height-1),l[1]<0&&(l[1]=0),l[1]>m.height-1&&(l[1]=m.height-1),l[0]>l[1]&&(l[0]=l[1]);break;case"S":a=1;1==t&&(a=r[0]);for(var c=l[0];c<=l[1]-a;c++)for(var f=0;fl[0]+a;c--)for(f=0;fl[0];c--)for(f=0;f=m.width&&(s=0,d++);break;default:console.log("Unknown terminal code",e,r,i)}}})(i,b,k+1,v),d=0);break;case 4:case 5:d=0;break;case 6:var o=i.charCodeAt(0);";"==i?k++:7==o?((e=>{var r;0!=e.length&&(0==(r=parseInt(e[0]))||2==r)&&1m.width&&(S=m.width),T>m.height-1&&(T=m.height-1),e){case"\b":0l[1]&&(m.recordLineTobackBuffer(0),x(1),T=l[1]),m.lineFeed="\r",S=0;break;case"\r":S=0;break;default:S>=m.width&&(S=0,C&&T++,T>=m.height-1)&&(x(1),T=m.height-1),o(e),S++}}}function o(e){y[T][S]=e,p[T][S]=(w<<6)+(u<<12)+g}function L(){for(var e=(w<<6)+(u<<12)+g,r=S;r")},m.TermDrawLine=function(e,r,t){for(var i,n,h,a,o=1,c=0;c>a&63],1&i&&(e+=";text-decoration:underline"),e+=';">',t=""+(t=""),o=i),n=y[r][c]){case"&":e+="&";break;case"<":e+="<";break;case">":e+=">";break;case" ":e+=" ";break;default:e+=n}return[e,t]},m.TermDraw=function(){for(var e="",r="",t=0;t")}var n=(B=800"+n+r+e+"",m.DivElement.scrollTop=m.DivElement.scrollHeight,0==m.heightLock&&setTimeout(m.TermLockHeight,10)},m.TermLockHeight=function(){m.heightLock=m.DivElement.clientHeight,m.DivElement.style.height=m.DivElement.parentNode.style.height=m.heightLock+"px",m.DivElement.style["overflow-y"]="scroll"},m.TermInit=function(){m.TermResetScreen()},m.heightLock=0,m.DivElement.style.height="",null!=r&&null!=r.cols&&null!=r.rows?m.Init(r.cols,r.rows):m.Init(),m} \ No newline at end of file diff --git a/public/scripts/amt-wsman-0.2.0-min.js b/public/scripts/amt-wsman-0.2.0-min.js index 286f8274..fe0e611e 100644 --- a/public/scripts/amt-wsman-0.2.0-min.js +++ b/public/scripts/amt-wsman-0.2.0-min.js @@ -1 +1 @@ -var WsmanStackCreateService=function(e,s,r,a,o,t){var u={};function l(e){if(!e)return"";var s,r=" ";for(s in e)e.hasOwnProperty(s)&&0===s.indexOf("@")&&(r+=s.substring(1)+'="'+e[s]+'" ');return r}function p(e){if(!e)return"";if("string"==typeof e)return e;if(e.InstanceID)return''+e.InstanceID+"";var s,r="";for(s in e)if(e.hasOwnProperty(s)){if(r+='',e[s].ReferenceParameters){var r=(r+="")+(""+e[s].Address+""+e[s].ReferenceParameters.ResourceURI+""),a=e[s].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(a))for(var o=0;o"+a[o].Value+"";else r+=""+a.Value+"";r+=""}else r+=e[s];r+=""}return r+=""}return u.NextMessageId=1,u.Address="/wsman",u.comm=CreateWsmanComm(e,s,r,a,o,t),u.PerformAjax=function(e,a,s,r,o){u.comm.PerformAjax('
"+e,function(e,s,r){200!=s?a(u,null,{Header:{HttpError:s}},s,r):(e=u.ParseWsman(e))&&null!=e?a(u,e.Header.ResourceURI,e,200,r):a(u,null,{Header:{HttpError:s}},601,r)},s,r)},u.CancelAllQueries=function(e){u.comm.CancelAllQueries(e)},u.GetNameFromUrl=function(e){var s=e.lastIndexOf("/");return-1==s?e:e.substring(s+1)},u.ExecSubscribe=function(e,s,r,a,o,t,n,l,d,c){var m="",i="",d=(null!=d&&null!=c&&(m="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"+d+''+c+"",i=''),l=null!=l?""+l+"":"","http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+p(n)+m+'
'+r+""+i+"PT0.000000S");u.PerformAjax(d+"
",a,o,t,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"')},u.ExecUnSubscribe=function(e,s,r,a,o){e="http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+p(o)+"";u.PerformAjax(e+"",s,r,a,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"')},u.ExecPut=function(e,s,r,a,o,t){t="http://schemas.xmlsoap.org/ws/2004/09/transfer/Put"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S"+p(t)+""+function(e,s){if(!e||null==s)return"";var r,a=u.GetNameFromUrl(e),o="';for(r in s)if(s.hasOwnProperty(r)&&0!==r.indexOf("__")&&0!==r.indexOf("@")&&void 0!==s[r]&&null!==s[r]&&"function"!=typeof s[r])if("object"==typeof s[r]&&s[r].ReferenceParameters){o+=""+s[r].Address+""+s[r].ReferenceParameters.ResourceURI+"";var t=s[r].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(t))for(var n=0;n"+t[n].Value+"";else o+=""+t.Value+"";o+=""}else if(Array.isArray(s[r]))for(n=0;n"+s[r][n].toString()+"";else o+=""+s[r].toString()+"";return o+=""}(e,s);u.PerformAjax(t+"",r,a,o)},u.ExecCreate=function(e,s,r,a,o,t){var n,l=u.GetNameFromUrl(e),d="http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+p(t)+"';for(n in s)d+=""+s[n]+"";u.PerformAjax(d+"",r,a,o)},u.ExecCreateXml=function(e,s,r,a,o){var t=u.GetNameFromUrl(e);u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S'+s+"",r,a,o)},u.ExecDelete=function(e,s,r,a,o){e="http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+p(s)+"";u.PerformAjax(e,r,a,o)},u.ExecGet=function(e,s,r,a){u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S",s,r,a)},u.ExecMethod=function(e,s,r,a,o,t,n){var l,d="";for(l in r)if(null!=r[l])if(Array.isArray(r[l]))for(var c in r[l])d+=""+r[l][c]+"";else d+=""+r[l]+"";u.ExecMethodXml(e,s,d,a,o,t,n)},u.ExecMethodXml=function(e,s,r,a,o,t,n){u.PerformAjax(e+"/"+s+""+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+p(n)+"'+r+"",a,o,t)},u.ExecEnum=function(e,s,r,a){u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate"+u.Address+""+e+""+u.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S',s,r,a)},u.ExecPull=function(e,s,r,a,o){u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"+u.Address+""+e+""+u.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+s+"99999999",r,a,o)},u.ParseWsman=function(s){try{s.childNodes||(s=function(e){{var s;return window.DOMParser?(new DOMParser).parseFromString(e,"text/xml"):((s=new ActiveXObject("Microsoft.XMLDOM")).async=!1,s.loadXML(e),s)}}(s));var e={Header:{}},r=s.getElementsByTagName("Header")[0];if(!(r=r||s.getElementsByTagName("a:Header")[0]))return null;for(var a=0;a'+e.InstanceID+"";var s,r="";for(s in e)if(e.hasOwnProperty(s)){if(r+='',e[s].ReferenceParameters){var r=(r+="")+(""+e[s].Address+""+e[s].ReferenceParameters.ResourceURI+""),a=e[s].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(a))for(var o=0;o"+a[o].Value+"";else r+=""+a.Value+"";r+=""}else r+=e[s];r+=""}return r+=""}return u.NextMessageId=1,u.Address="/wsman",u.comm=CreateWsmanComm(e,s,r,a,o,t),u.PerformAjax=function(e,a,s,r,o){u.comm.PerformAjax('
"+e,function(e,s,r){200!=s?a(u,null,{Header:{HttpError:s}},s,r):(e=u.ParseWsman(e))&&null!=e?a(u,e.Header.ResourceURI,e,200,r):a(u,null,{Header:{HttpError:s}},601,r)},s,r)},u.CancelAllQueries=function(e){u.comm.CancelAllQueries(e)},u.GetNameFromUrl=function(e){var s=e.lastIndexOf("/");return-1==s?e:e.substring(s+1)},u.ExecSubscribe=function(e,s,r,a,o,t,n,l,c,d){var m="",i="",c=(null!=c&&null!=d&&(m="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"+c+''+d+"",i=''),l=null!=l?""+l+"":"","http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+p(n)+m+'
'+r+""+i+"PT0.000000S");u.PerformAjax(c+"
",a,o,t,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"')},u.ExecUnSubscribe=function(e,s,r,a,o){e="http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+p(o)+"";u.PerformAjax(e+"",s,r,a,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"')},u.ExecPut=function(e,s,r,a,o,t){t="http://schemas.xmlsoap.org/ws/2004/09/transfer/Put"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S"+p(t)+""+((e,s)=>{if(!e||null==s)return"";var r,a=u.GetNameFromUrl(e),o="';for(r in s)if(s.hasOwnProperty(r)&&0!==r.indexOf("__")&&0!==r.indexOf("@")&&null!=s[r]&&"function"!=typeof s[r])if("object"==typeof s[r]&&s[r].ReferenceParameters){o+=""+s[r].Address+""+s[r].ReferenceParameters.ResourceURI+"";var t=s[r].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(t))for(var n=0;n"+t[n].Value+"";else o+=""+t.Value+"";o+=""}else if(Array.isArray(s[r]))for(n=0;n"+s[r][n].toString()+"";else o+=""+s[r].toString()+"";return o+=""})(e,s);u.PerformAjax(t+"",r,a,o)},u.ExecCreate=function(e,s,r,a,o,t){var n,l=u.GetNameFromUrl(e),c="http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+p(t)+"';for(n in s)c+=""+s[n]+"";u.PerformAjax(c+"",r,a,o)},u.ExecCreateXml=function(e,s,r,a,o){var t=u.GetNameFromUrl(e);u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S'+s+"",r,a,o)},u.ExecDelete=function(e,s,r,a,o){e="http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+p(s)+"";u.PerformAjax(e,r,a,o)},u.ExecGet=function(e,s,r,a){u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get"+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S",s,r,a)},u.ExecMethod=function(e,s,r,a,o,t,n){var l,c="";for(l in r)if(null!=r[l])if(Array.isArray(r[l]))for(var d in r[l])c+=""+r[l][d]+"";else c+=""+r[l]+"";u.ExecMethodXml(e,s,c,a,o,t,n)},u.ExecMethodXml=function(e,s,r,a,o,t,n){u.PerformAjax(e+"/"+s+""+u.Address+""+e+""+u.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+p(n)+"'+r+"",a,o,t)},u.ExecEnum=function(e,s,r,a){u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate"+u.Address+""+e+""+u.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S',s,r,a)},u.ExecPull=function(e,s,r,a,o){u.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"+u.Address+""+e+""+u.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+s+"99999999",r,a,o)},u.ParseWsman=function(s){try{s.childNodes||(s=(e=>{var s;return window.DOMParser?(new DOMParser).parseFromString(e,"text/xml"):((s=new ActiveXObject("Microsoft.XMLDOM")).async=!1,s.loadXML(e),s)})(s));var e={Header:{}},r=s.getElementsByTagName("Header")[0];if(!(r=r||s.getElementsByTagName("a:Header")[0]))return null;for(var a=0;at.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",jt="collapsing",Mt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(jt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(jt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Mt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function je(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const Me={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:je(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:je(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,jn=`hide${xn}`,Mn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,jn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Mn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Mn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",js="Home",Ms="End",Fs="active",Hs="fade",Ws="show",Bs=".dropdown-toggle",zs=`:not(${Bs})`,Rs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',qs=`.nav-link${zs}, .list-group-item${zs}, [role="tab"]${zs}, ${Rs}`,Vs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Ks extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,js,Ms].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([js,Ms].includes(t.key))i=e[t.key===js?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Ks.getOrCreateInstance(i).show())}_getChildren(){return z.find(qs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Bs,Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(qs)?t:z.findOne(qs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Ks.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,Rs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Ks.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(Vs))Ks.getOrCreateInstance(t)})),m(Ks);const Qs=".bs.toast",Xs=`mouseover${Qs}`,Ys=`mouseout${Qs}`,Us=`focusin${Qs}`,Gs=`focusout${Qs}`,Js=`hide${Qs}`,Zs=`hidden${Qs}`,to=`show${Qs}`,eo=`shown${Qs}`,io="hide",no="show",so="showing",oo={animation:"boolean",autohide:"boolean",delay:"number"},ro={animation:!0,autohide:!0,delay:5e3};class ao extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return ro}static get DefaultType(){return oo}static get NAME(){return"toast"}show(){N.trigger(this._element,to).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(io),d(this._element),this._element.classList.add(no,so),this._queueCallback((()=>{this._element.classList.remove(so),N.trigger(this._element,eo),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Js).defaultPrevented||(this._element.classList.add(so),this._queueCallback((()=>{this._element.classList.add(io),this._element.classList.remove(so,no),N.trigger(this._element,Zs)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(no),super.dispose()}isShown(){return this._element.classList.contains(no)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Xs,(t=>this._onInteraction(t,!0))),N.on(this._element,Ys,(t=>this._onInteraction(t,!1))),N.on(this._element,Us,(t=>this._onInteraction(t,!0))),N.on(this._element,Gs,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ao.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ao),m(ao),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Ks,Toast:ao,Tooltip:cs}})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/public/scripts/bootstrap.js b/public/scripts/bootstrap.js new file mode 100644 index 00000000..7afb8336 --- /dev/null +++ b/public/scripts/bootstrap.js @@ -0,0 +1,6314 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory()); +})(this, (function () { 'use strict'; + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/data.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + /** + * Constants + */ + + const elementMap = new Map(); + const Data = { + set(element, key, instance) { + if (!elementMap.has(element)) { + elementMap.set(element, new Map()); + } + const instanceMap = elementMap.get(element); + + // make it clear we only want one instance per element + // can be removed later when multiple key/instances are fine to be used + if (!instanceMap.has(key) && instanceMap.size !== 0) { + // eslint-disable-next-line no-console + console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`); + return; + } + instanceMap.set(key, instance); + }, + get(element, key) { + if (elementMap.has(element)) { + return elementMap.get(element).get(key) || null; + } + return null; + }, + remove(element, key) { + if (!elementMap.has(element)) { + return; + } + const instanceMap = elementMap.get(element); + instanceMap.delete(key); + + // free up element references if there are no instances left for an element + if (instanceMap.size === 0) { + elementMap.delete(element); + } + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/index.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const MAX_UID = 1000000; + const MILLISECONDS_MULTIPLIER = 1000; + const TRANSITION_END = 'transitionend'; + + /** + * Properly escape IDs selectors to handle weird IDs + * @param {string} selector + * @returns {string} + */ + const parseSelector = selector => { + if (selector && window.CSS && window.CSS.escape) { + // document.querySelector needs escaping to handle IDs (html5+) containing for instance / + selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`); + } + return selector; + }; + + // Shout-out Angus Croll (https://goo.gl/pxwQGp) + const toType = object => { + if (object === null || object === undefined) { + return `${object}`; + } + return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase(); + }; + + /** + * Public Util API + */ + + const getUID = prefix => { + do { + prefix += Math.floor(Math.random() * MAX_UID); + } while (document.getElementById(prefix)); + return prefix; + }; + const getTransitionDurationFromElement = element => { + if (!element) { + return 0; + } + + // Get transition-duration of the element + let { + transitionDuration, + transitionDelay + } = window.getComputedStyle(element); + const floatTransitionDuration = Number.parseFloat(transitionDuration); + const floatTransitionDelay = Number.parseFloat(transitionDelay); + + // Return 0 if element or transition duration is not found + if (!floatTransitionDuration && !floatTransitionDelay) { + return 0; + } + + // If multiple durations are defined, take the first + transitionDuration = transitionDuration.split(',')[0]; + transitionDelay = transitionDelay.split(',')[0]; + return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; + }; + const triggerTransitionEnd = element => { + element.dispatchEvent(new Event(TRANSITION_END)); + }; + const isElement$1 = object => { + if (!object || typeof object !== 'object') { + return false; + } + if (typeof object.jquery !== 'undefined') { + object = object[0]; + } + return typeof object.nodeType !== 'undefined'; + }; + const getElement = object => { + // it's a jQuery object or a node element + if (isElement$1(object)) { + return object.jquery ? object[0] : object; + } + if (typeof object === 'string' && object.length > 0) { + return document.querySelector(parseSelector(object)); + } + return null; + }; + const isVisible = element => { + if (!isElement$1(element) || element.getClientRects().length === 0) { + return false; + } + const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'; + // Handle `details` element as its content may falsie appear visible when it is closed + const closedDetails = element.closest('details:not([open])'); + if (!closedDetails) { + return elementIsVisible; + } + if (closedDetails !== element) { + const summary = element.closest('summary'); + if (summary && summary.parentNode !== closedDetails) { + return false; + } + if (summary === null) { + return false; + } + } + return elementIsVisible; + }; + const isDisabled = element => { + if (!element || element.nodeType !== Node.ELEMENT_NODE) { + return true; + } + if (element.classList.contains('disabled')) { + return true; + } + if (typeof element.disabled !== 'undefined') { + return element.disabled; + } + return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; + }; + const findShadowRoot = element => { + if (!document.documentElement.attachShadow) { + return null; + } + + // Can find the shadow root otherwise it'll return the document + if (typeof element.getRootNode === 'function') { + const root = element.getRootNode(); + return root instanceof ShadowRoot ? root : null; + } + if (element instanceof ShadowRoot) { + return element; + } + + // when we don't find a shadow root + if (!element.parentNode) { + return null; + } + return findShadowRoot(element.parentNode); + }; + const noop = () => {}; + + /** + * Trick to restart an element's animation + * + * @param {HTMLElement} element + * @return void + * + * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation + */ + const reflow = element => { + element.offsetHeight; // eslint-disable-line no-unused-expressions + }; + const getjQuery = () => { + if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { + return window.jQuery; + } + return null; + }; + const DOMContentLoadedCallbacks = []; + const onDOMContentLoaded = callback => { + if (document.readyState === 'loading') { + // add listener on the first call when the document is in loading state + if (!DOMContentLoadedCallbacks.length) { + document.addEventListener('DOMContentLoaded', () => { + for (const callback of DOMContentLoadedCallbacks) { + callback(); + } + }); + } + DOMContentLoadedCallbacks.push(callback); + } else { + callback(); + } + }; + const isRTL = () => document.documentElement.dir === 'rtl'; + const defineJQueryPlugin = plugin => { + onDOMContentLoaded(() => { + const $ = getjQuery(); + /* istanbul ignore if */ + if ($) { + const name = plugin.NAME; + const JQUERY_NO_CONFLICT = $.fn[name]; + $.fn[name] = plugin.jQueryInterface; + $.fn[name].Constructor = plugin; + $.fn[name].noConflict = () => { + $.fn[name] = JQUERY_NO_CONFLICT; + return plugin.jQueryInterface; + }; + } + }); + }; + const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => { + return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue; + }; + const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { + if (!waitForTransition) { + execute(callback); + return; + } + const durationPadding = 5; + const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding; + let called = false; + const handler = ({ + target + }) => { + if (target !== transitionElement) { + return; + } + called = true; + transitionElement.removeEventListener(TRANSITION_END, handler); + execute(callback); + }; + transitionElement.addEventListener(TRANSITION_END, handler); + setTimeout(() => { + if (!called) { + triggerTransitionEnd(transitionElement); + } + }, emulatedDuration); + }; + + /** + * Return the previous/next element of a list. + * + * @param {array} list The list of elements + * @param activeElement The active element + * @param shouldGetNext Choose to get next or previous element + * @param isCycleAllowed + * @return {Element|elem} The proper element + */ + const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { + const listLength = list.length; + let index = list.indexOf(activeElement); + + // if the element does not exist in the list return an element + // depending on the direction and if cycle is allowed + if (index === -1) { + return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]; + } + index += shouldGetNext ? 1 : -1; + if (isCycleAllowed) { + index = (index + listLength) % listLength; + } + return list[Math.max(0, Math.min(index, listLength - 1))]; + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/event-handler.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const namespaceRegex = /[^.]*(?=\..*)\.|.*/; + const stripNameRegex = /\..*/; + const stripUidRegex = /::\d+$/; + const eventRegistry = {}; // Events storage + let uidEvent = 1; + const customEvents = { + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }; + const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']); + + /** + * Private methods + */ + + function makeEventUid(element, uid) { + return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; + } + function getElementEvents(element) { + const uid = makeEventUid(element); + element.uidEvent = uid; + eventRegistry[uid] = eventRegistry[uid] || {}; + return eventRegistry[uid]; + } + function bootstrapHandler(element, fn) { + return function handler(event) { + hydrateObj(event, { + delegateTarget: element + }); + if (handler.oneOff) { + EventHandler.off(element, event.type, fn); + } + return fn.apply(element, [event]); + }; + } + function bootstrapDelegationHandler(element, selector, fn) { + return function handler(event) { + const domElements = element.querySelectorAll(selector); + for (let { + target + } = event; target && target !== this; target = target.parentNode) { + for (const domElement of domElements) { + if (domElement !== target) { + continue; + } + hydrateObj(event, { + delegateTarget: target + }); + if (handler.oneOff) { + EventHandler.off(element, event.type, selector, fn); + } + return fn.apply(target, [event]); + } + } + }; + } + function findHandler(events, callable, delegationSelector = null) { + return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector); + } + function normalizeParameters(originalTypeEvent, handler, delegationFunction) { + const isDelegated = typeof handler === 'string'; + // TODO: tooltip passes `false` instead of selector, so we need to check + const callable = isDelegated ? delegationFunction : handler || delegationFunction; + let typeEvent = getTypeEvent(originalTypeEvent); + if (!nativeEvents.has(typeEvent)) { + typeEvent = originalTypeEvent; + } + return [isDelegated, callable, typeEvent]; + } + function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); + + // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position + // this prevents the handler from being dispatched the same way as mouseover or mouseout does + if (originalTypeEvent in customEvents) { + const wrapFunction = fn => { + return function (event) { + if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { + return fn.call(this, event); + } + }; + }; + callable = wrapFunction(callable); + } + const events = getElementEvents(element); + const handlers = events[typeEvent] || (events[typeEvent] = {}); + const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null); + if (previousFunction) { + previousFunction.oneOff = previousFunction.oneOff && oneOff; + return; + } + const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, '')); + const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable); + fn.delegationSelector = isDelegated ? handler : null; + fn.callable = callable; + fn.oneOff = oneOff; + fn.uidEvent = uid; + handlers[uid] = fn; + element.addEventListener(typeEvent, fn, isDelegated); + } + function removeHandler(element, events, typeEvent, handler, delegationSelector) { + const fn = findHandler(events[typeEvent], handler, delegationSelector); + if (!fn) { + return; + } + element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); + delete events[typeEvent][fn.uidEvent]; + } + function removeNamespacedHandlers(element, events, typeEvent, namespace) { + const storeElementEvent = events[typeEvent] || {}; + for (const [handlerKey, event] of Object.entries(storeElementEvent)) { + if (handlerKey.includes(namespace)) { + removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); + } + } + } + function getTypeEvent(event) { + // allow to get the native events from namespaced events ('click.bs.button' --> 'click') + event = event.replace(stripNameRegex, ''); + return customEvents[event] || event; + } + const EventHandler = { + on(element, event, handler, delegationFunction) { + addHandler(element, event, handler, delegationFunction, false); + }, + one(element, event, handler, delegationFunction) { + addHandler(element, event, handler, delegationFunction, true); + }, + off(element, originalTypeEvent, handler, delegationFunction) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); + const inNamespace = typeEvent !== originalTypeEvent; + const events = getElementEvents(element); + const storeElementEvent = events[typeEvent] || {}; + const isNamespace = originalTypeEvent.startsWith('.'); + if (typeof callable !== 'undefined') { + // Simplest case: handler is passed, remove that listener ONLY. + if (!Object.keys(storeElementEvent).length) { + return; + } + removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null); + return; + } + if (isNamespace) { + for (const elementEvent of Object.keys(events)) { + removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); + } + } + for (const [keyHandlers, event] of Object.entries(storeElementEvent)) { + const handlerKey = keyHandlers.replace(stripUidRegex, ''); + if (!inNamespace || originalTypeEvent.includes(handlerKey)) { + removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); + } + } + }, + trigger(element, event, args) { + if (typeof event !== 'string' || !element) { + return null; + } + const $ = getjQuery(); + const typeEvent = getTypeEvent(event); + const inNamespace = event !== typeEvent; + let jQueryEvent = null; + let bubbles = true; + let nativeDispatch = true; + let defaultPrevented = false; + if (inNamespace && $) { + jQueryEvent = $.Event(event, args); + $(element).trigger(jQueryEvent); + bubbles = !jQueryEvent.isPropagationStopped(); + nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); + defaultPrevented = jQueryEvent.isDefaultPrevented(); + } + const evt = hydrateObj(new Event(event, { + bubbles, + cancelable: true + }), args); + if (defaultPrevented) { + evt.preventDefault(); + } + if (nativeDispatch) { + element.dispatchEvent(evt); + } + if (evt.defaultPrevented && jQueryEvent) { + jQueryEvent.preventDefault(); + } + return evt; + } + }; + function hydrateObj(obj, meta = {}) { + for (const [key, value] of Object.entries(meta)) { + try { + obj[key] = value; + } catch (_unused) { + Object.defineProperty(obj, key, { + configurable: true, + get() { + return value; + } + }); + } + } + return obj; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/manipulator.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + function normalizeData(value) { + if (value === 'true') { + return true; + } + if (value === 'false') { + return false; + } + if (value === Number(value).toString()) { + return Number(value); + } + if (value === '' || value === 'null') { + return null; + } + if (typeof value !== 'string') { + return value; + } + try { + return JSON.parse(decodeURIComponent(value)); + } catch (_unused) { + return value; + } + } + function normalizeDataKey(key) { + return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`); + } + const Manipulator = { + setDataAttribute(element, key, value) { + element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value); + }, + removeDataAttribute(element, key) { + element.removeAttribute(`data-bs-${normalizeDataKey(key)}`); + }, + getDataAttributes(element) { + if (!element) { + return {}; + } + const attributes = {}; + const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig')); + for (const key of bsKeys) { + let pureKey = key.replace(/^bs/, ''); + pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length); + attributes[pureKey] = normalizeData(element.dataset[key]); + } + return attributes; + }, + getDataAttribute(element, key) { + return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`)); + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/config.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Class definition + */ + + class Config { + // Getters + static get Default() { + return {}; + } + static get DefaultType() { + return {}; + } + static get NAME() { + throw new Error('You have to implement the static method "NAME", for each component!'); + } + _getConfig(config) { + config = this._mergeConfigObj(config); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + _configAfterMerge(config) { + return config; + } + _mergeConfigObj(config, element) { + const jsonConfig = isElement$1(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse + + return { + ...this.constructor.Default, + ...(typeof jsonConfig === 'object' ? jsonConfig : {}), + ...(isElement$1(element) ? Manipulator.getDataAttributes(element) : {}), + ...(typeof config === 'object' ? config : {}) + }; + } + _typeCheckConfig(config, configTypes = this.constructor.DefaultType) { + for (const [property, expectedTypes] of Object.entries(configTypes)) { + const value = config[property]; + const valueType = isElement$1(value) ? 'element' : toType(value); + if (!new RegExp(expectedTypes).test(valueType)) { + throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`); + } + } + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap base-component.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const VERSION = '5.3.3'; + + /** + * Class definition + */ + + class BaseComponent extends Config { + constructor(element, config) { + super(); + element = getElement(element); + if (!element) { + return; + } + this._element = element; + this._config = this._getConfig(config); + Data.set(this._element, this.constructor.DATA_KEY, this); + } + + // Public + dispose() { + Data.remove(this._element, this.constructor.DATA_KEY); + EventHandler.off(this._element, this.constructor.EVENT_KEY); + for (const propertyName of Object.getOwnPropertyNames(this)) { + this[propertyName] = null; + } + } + _queueCallback(callback, element, isAnimated = true) { + executeAfterTransition(callback, element, isAnimated); + } + _getConfig(config) { + config = this._mergeConfigObj(config, this._element); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + + // Static + static getInstance(element) { + return Data.get(getElement(element), this.DATA_KEY); + } + static getOrCreateInstance(element, config = {}) { + return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null); + } + static get VERSION() { + return VERSION; + } + static get DATA_KEY() { + return `bs.${this.NAME}`; + } + static get EVENT_KEY() { + return `.${this.DATA_KEY}`; + } + static eventName(name) { + return `${name}${this.EVENT_KEY}`; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/selector-engine.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const getSelector = element => { + let selector = element.getAttribute('data-bs-target'); + if (!selector || selector === '#') { + let hrefAttribute = element.getAttribute('href'); + + // The only valid content that could double as a selector are IDs or classes, + // so everything starting with `#` or `.`. If a "real" URL is used as the selector, + // `document.querySelector` will rightfully complain it is invalid. + // See https://github.com/twbs/bootstrap/issues/32273 + if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) { + return null; + } + + // Just in case some CMS puts out a full URL with the anchor appended + if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) { + hrefAttribute = `#${hrefAttribute.split('#')[1]}`; + } + selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null; + } + return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null; + }; + const SelectorEngine = { + find(selector, element = document.documentElement) { + return [].concat(...Element.prototype.querySelectorAll.call(element, selector)); + }, + findOne(selector, element = document.documentElement) { + return Element.prototype.querySelector.call(element, selector); + }, + children(element, selector) { + return [].concat(...element.children).filter(child => child.matches(selector)); + }, + parents(element, selector) { + const parents = []; + let ancestor = element.parentNode.closest(selector); + while (ancestor) { + parents.push(ancestor); + ancestor = ancestor.parentNode.closest(selector); + } + return parents; + }, + prev(element, selector) { + let previous = element.previousElementSibling; + while (previous) { + if (previous.matches(selector)) { + return [previous]; + } + previous = previous.previousElementSibling; + } + return []; + }, + // TODO: this is now unused; remove later along with prev() + next(element, selector) { + let next = element.nextElementSibling; + while (next) { + if (next.matches(selector)) { + return [next]; + } + next = next.nextElementSibling; + } + return []; + }, + focusableChildren(element) { + const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(','); + return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)); + }, + getSelectorFromElement(element) { + const selector = getSelector(element); + if (selector) { + return SelectorEngine.findOne(selector) ? selector : null; + } + return null; + }, + getElementFromSelector(element) { + const selector = getSelector(element); + return selector ? SelectorEngine.findOne(selector) : null; + }, + getMultipleElementsFromSelector(element) { + const selector = getSelector(element); + return selector ? SelectorEngine.find(selector) : []; + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/component-functions.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const enableDismissTrigger = (component, method = 'hide') => { + const clickEvent = `click.dismiss${component.EVENT_KEY}`; + const name = component.NAME; + EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`); + const instance = component.getOrCreateInstance(target); + + // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method + instance[method](); + }); + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$f = 'alert'; + const DATA_KEY$a = 'bs.alert'; + const EVENT_KEY$b = `.${DATA_KEY$a}`; + const EVENT_CLOSE = `close${EVENT_KEY$b}`; + const EVENT_CLOSED = `closed${EVENT_KEY$b}`; + const CLASS_NAME_FADE$5 = 'fade'; + const CLASS_NAME_SHOW$8 = 'show'; + + /** + * Class definition + */ + + class Alert extends BaseComponent { + // Getters + static get NAME() { + return NAME$f; + } + + // Public + close() { + const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE); + if (closeEvent.defaultPrevented) { + return; + } + this._element.classList.remove(CLASS_NAME_SHOW$8); + const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5); + this._queueCallback(() => this._destroyElement(), this._element, isAnimated); + } + + // Private + _destroyElement() { + this._element.remove(); + EventHandler.trigger(this._element, EVENT_CLOSED); + this.dispose(); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Alert.getOrCreateInstance(this); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + }); + } + } + + /** + * Data API implementation + */ + + enableDismissTrigger(Alert, 'close'); + + /** + * jQuery + */ + + defineJQueryPlugin(Alert); + + /** + * -------------------------------------------------------------------------- + * Bootstrap button.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$e = 'button'; + const DATA_KEY$9 = 'bs.button'; + const EVENT_KEY$a = `.${DATA_KEY$9}`; + const DATA_API_KEY$6 = '.data-api'; + const CLASS_NAME_ACTIVE$3 = 'active'; + const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]'; + const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`; + + /** + * Class definition + */ + + class Button extends BaseComponent { + // Getters + static get NAME() { + return NAME$e; + } + + // Public + toggle() { + // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method + this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3)); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Button.getOrCreateInstance(this); + if (config === 'toggle') { + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => { + event.preventDefault(); + const button = event.target.closest(SELECTOR_DATA_TOGGLE$5); + const data = Button.getOrCreateInstance(button); + data.toggle(); + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Button); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/swipe.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$d = 'swipe'; + const EVENT_KEY$9 = '.bs.swipe'; + const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`; + const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`; + const EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`; + const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`; + const EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`; + const POINTER_TYPE_TOUCH = 'touch'; + const POINTER_TYPE_PEN = 'pen'; + const CLASS_NAME_POINTER_EVENT = 'pointer-event'; + const SWIPE_THRESHOLD = 40; + const Default$c = { + endCallback: null, + leftCallback: null, + rightCallback: null + }; + const DefaultType$c = { + endCallback: '(function|null)', + leftCallback: '(function|null)', + rightCallback: '(function|null)' + }; + + /** + * Class definition + */ + + class Swipe extends Config { + constructor(element, config) { + super(); + this._element = element; + if (!element || !Swipe.isSupported()) { + return; + } + this._config = this._getConfig(config); + this._deltaX = 0; + this._supportPointerEvents = Boolean(window.PointerEvent); + this._initEvents(); + } + + // Getters + static get Default() { + return Default$c; + } + static get DefaultType() { + return DefaultType$c; + } + static get NAME() { + return NAME$d; + } + + // Public + dispose() { + EventHandler.off(this._element, EVENT_KEY$9); + } + + // Private + _start(event) { + if (!this._supportPointerEvents) { + this._deltaX = event.touches[0].clientX; + return; + } + if (this._eventIsPointerPenTouch(event)) { + this._deltaX = event.clientX; + } + } + _end(event) { + if (this._eventIsPointerPenTouch(event)) { + this._deltaX = event.clientX - this._deltaX; + } + this._handleSwipe(); + execute(this._config.endCallback); + } + _move(event) { + this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX; + } + _handleSwipe() { + const absDeltaX = Math.abs(this._deltaX); + if (absDeltaX <= SWIPE_THRESHOLD) { + return; + } + const direction = absDeltaX / this._deltaX; + this._deltaX = 0; + if (!direction) { + return; + } + execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback); + } + _initEvents() { + if (this._supportPointerEvents) { + EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event)); + EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event)); + this._element.classList.add(CLASS_NAME_POINTER_EVENT); + } else { + EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event)); + EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event)); + EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event)); + } + } + _eventIsPointerPenTouch(event) { + return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH); + } + + // Static + static isSupported() { + return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$c = 'carousel'; + const DATA_KEY$8 = 'bs.carousel'; + const EVENT_KEY$8 = `.${DATA_KEY$8}`; + const DATA_API_KEY$5 = '.data-api'; + const ARROW_LEFT_KEY$1 = 'ArrowLeft'; + const ARROW_RIGHT_KEY$1 = 'ArrowRight'; + const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + const ORDER_NEXT = 'next'; + const ORDER_PREV = 'prev'; + const DIRECTION_LEFT = 'left'; + const DIRECTION_RIGHT = 'right'; + const EVENT_SLIDE = `slide${EVENT_KEY$8}`; + const EVENT_SLID = `slid${EVENT_KEY$8}`; + const EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`; + const EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`; + const EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`; + const EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`; + const EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`; + const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`; + const CLASS_NAME_CAROUSEL = 'carousel'; + const CLASS_NAME_ACTIVE$2 = 'active'; + const CLASS_NAME_SLIDE = 'slide'; + const CLASS_NAME_END = 'carousel-item-end'; + const CLASS_NAME_START = 'carousel-item-start'; + const CLASS_NAME_NEXT = 'carousel-item-next'; + const CLASS_NAME_PREV = 'carousel-item-prev'; + const SELECTOR_ACTIVE = '.active'; + const SELECTOR_ITEM = '.carousel-item'; + const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM; + const SELECTOR_ITEM_IMG = '.carousel-item img'; + const SELECTOR_INDICATORS = '.carousel-indicators'; + const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'; + const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'; + const KEY_TO_DIRECTION = { + [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT, + [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT + }; + const Default$b = { + interval: 5000, + keyboard: true, + pause: 'hover', + ride: false, + touch: true, + wrap: true + }; + const DefaultType$b = { + interval: '(number|boolean)', + // TODO:v6 remove boolean support + keyboard: 'boolean', + pause: '(string|boolean)', + ride: '(boolean|string)', + touch: 'boolean', + wrap: 'boolean' + }; + + /** + * Class definition + */ + + class Carousel extends BaseComponent { + constructor(element, config) { + super(element, config); + this._interval = null; + this._activeElement = null; + this._isSliding = false; + this.touchTimeout = null; + this._swipeHelper = null; + this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); + this._addEventListeners(); + if (this._config.ride === CLASS_NAME_CAROUSEL) { + this.cycle(); + } + } + + // Getters + static get Default() { + return Default$b; + } + static get DefaultType() { + return DefaultType$b; + } + static get NAME() { + return NAME$c; + } + + // Public + next() { + this._slide(ORDER_NEXT); + } + nextWhenVisible() { + // FIXME TODO use `document.visibilityState` + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && isVisible(this._element)) { + this.next(); + } + } + prev() { + this._slide(ORDER_PREV); + } + pause() { + if (this._isSliding) { + triggerTransitionEnd(this._element); + } + this._clearInterval(); + } + cycle() { + this._clearInterval(); + this._updateInterval(); + this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval); + } + _maybeEnableCycle() { + if (!this._config.ride) { + return; + } + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.cycle()); + return; + } + this.cycle(); + } + to(index) { + const items = this._getItems(); + if (index > items.length - 1 || index < 0) { + return; + } + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.to(index)); + return; + } + const activeIndex = this._getItemIndex(this._getActive()); + if (activeIndex === index) { + return; + } + const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV; + this._slide(order, items[index]); + } + dispose() { + if (this._swipeHelper) { + this._swipeHelper.dispose(); + } + super.dispose(); + } + + // Private + _configAfterMerge(config) { + config.defaultInterval = config.interval; + return config; + } + _addEventListeners() { + if (this._config.keyboard) { + EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event)); + } + if (this._config.pause === 'hover') { + EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause()); + EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle()); + } + if (this._config.touch && Swipe.isSupported()) { + this._addTouchEventListeners(); + } + } + _addTouchEventListeners() { + for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) { + EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault()); + } + const endCallBack = () => { + if (this._config.pause !== 'hover') { + return; + } + + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + + this.pause(); + if (this.touchTimeout) { + clearTimeout(this.touchTimeout); + } + this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval); + }; + const swipeConfig = { + leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)), + rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)), + endCallback: endCallBack + }; + this._swipeHelper = new Swipe(this._element, swipeConfig); + } + _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + const direction = KEY_TO_DIRECTION[event.key]; + if (direction) { + event.preventDefault(); + this._slide(this._directionToOrder(direction)); + } + } + _getItemIndex(element) { + return this._getItems().indexOf(element); + } + _setActiveIndicatorElement(index) { + if (!this._indicatorsElement) { + return; + } + const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement); + activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2); + activeIndicator.removeAttribute('aria-current'); + const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement); + if (newActiveIndicator) { + newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2); + newActiveIndicator.setAttribute('aria-current', 'true'); + } + } + _updateInterval() { + const element = this._activeElement || this._getActive(); + if (!element) { + return; + } + const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10); + this._config.interval = elementInterval || this._config.defaultInterval; + } + _slide(order, element = null) { + if (this._isSliding) { + return; + } + const activeElement = this._getActive(); + const isNext = order === ORDER_NEXT; + const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap); + if (nextElement === activeElement) { + return; + } + const nextElementIndex = this._getItemIndex(nextElement); + const triggerEvent = eventName => { + return EventHandler.trigger(this._element, eventName, { + relatedTarget: nextElement, + direction: this._orderToDirection(order), + from: this._getItemIndex(activeElement), + to: nextElementIndex + }); + }; + const slideEvent = triggerEvent(EVENT_SLIDE); + if (slideEvent.defaultPrevented) { + return; + } + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + // TODO: change tests that use empty divs to avoid this check + return; + } + const isCycling = Boolean(this._interval); + this.pause(); + this._isSliding = true; + this._setActiveIndicatorElement(nextElementIndex); + this._activeElement = nextElement; + const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END; + const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV; + nextElement.classList.add(orderClassName); + reflow(nextElement); + activeElement.classList.add(directionalClassName); + nextElement.classList.add(directionalClassName); + const completeCallBack = () => { + nextElement.classList.remove(directionalClassName, orderClassName); + nextElement.classList.add(CLASS_NAME_ACTIVE$2); + activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName); + this._isSliding = false; + triggerEvent(EVENT_SLID); + }; + this._queueCallback(completeCallBack, activeElement, this._isAnimated()); + if (isCycling) { + this.cycle(); + } + } + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_SLIDE); + } + _getActive() { + return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); + } + _getItems() { + return SelectorEngine.find(SELECTOR_ITEM, this._element); + } + _clearInterval() { + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + } + _directionToOrder(direction) { + if (isRTL()) { + return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT; + } + return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV; + } + _orderToDirection(order) { + if (isRTL()) { + return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Carousel.getOrCreateInstance(this, config); + if (typeof config === 'number') { + data.to(config); + return; + } + if (typeof config === 'string') { + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { + return; + } + event.preventDefault(); + const carousel = Carousel.getOrCreateInstance(target); + const slideIndex = this.getAttribute('data-bs-slide-to'); + if (slideIndex) { + carousel.to(slideIndex); + carousel._maybeEnableCycle(); + return; + } + if (Manipulator.getDataAttribute(this, 'slide') === 'next') { + carousel.next(); + carousel._maybeEnableCycle(); + return; + } + carousel.prev(); + carousel._maybeEnableCycle(); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => { + const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE); + for (const carousel of carousels) { + Carousel.getOrCreateInstance(carousel); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Carousel); + + /** + * -------------------------------------------------------------------------- + * Bootstrap collapse.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$b = 'collapse'; + const DATA_KEY$7 = 'bs.collapse'; + const EVENT_KEY$7 = `.${DATA_KEY$7}`; + const DATA_API_KEY$4 = '.data-api'; + const EVENT_SHOW$6 = `show${EVENT_KEY$7}`; + const EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`; + const EVENT_HIDE$6 = `hide${EVENT_KEY$7}`; + const EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`; + const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`; + const CLASS_NAME_SHOW$7 = 'show'; + const CLASS_NAME_COLLAPSE = 'collapse'; + const CLASS_NAME_COLLAPSING = 'collapsing'; + const CLASS_NAME_COLLAPSED = 'collapsed'; + const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`; + const CLASS_NAME_HORIZONTAL = 'collapse-horizontal'; + const WIDTH = 'width'; + const HEIGHT = 'height'; + const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'; + const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]'; + const Default$a = { + parent: null, + toggle: true + }; + const DefaultType$a = { + parent: '(null|element)', + toggle: 'boolean' + }; + + /** + * Class definition + */ + + class Collapse extends BaseComponent { + constructor(element, config) { + super(element, config); + this._isTransitioning = false; + this._triggerArray = []; + const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4); + for (const elem of toggleList) { + const selector = SelectorEngine.getSelectorFromElement(elem); + const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element); + if (selector !== null && filterElement.length) { + this._triggerArray.push(elem); + } + } + this._initializeChildren(); + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._triggerArray, this._isShown()); + } + if (this._config.toggle) { + this.toggle(); + } + } + + // Getters + static get Default() { + return Default$a; + } + static get DefaultType() { + return DefaultType$a; + } + static get NAME() { + return NAME$b; + } + + // Public + toggle() { + if (this._isShown()) { + this.hide(); + } else { + this.show(); + } + } + show() { + if (this._isTransitioning || this._isShown()) { + return; + } + let activeChildren = []; + + // find active children + if (this._config.parent) { + activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, { + toggle: false + })); + } + if (activeChildren.length && activeChildren[0]._isTransitioning) { + return; + } + const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6); + if (startEvent.defaultPrevented) { + return; + } + for (const activeInstance of activeChildren) { + activeInstance.hide(); + } + const dimension = this._getDimension(); + this._element.classList.remove(CLASS_NAME_COLLAPSE); + this._element.classList.add(CLASS_NAME_COLLAPSING); + this._element.style[dimension] = 0; + this._addAriaAndCollapsedClass(this._triggerArray, true); + this._isTransitioning = true; + const complete = () => { + this._isTransitioning = false; + this._element.classList.remove(CLASS_NAME_COLLAPSING); + this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + this._element.style[dimension] = ''; + EventHandler.trigger(this._element, EVENT_SHOWN$6); + }; + const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + const scrollSize = `scroll${capitalizedDimension}`; + this._queueCallback(complete, this._element, true); + this._element.style[dimension] = `${this._element[scrollSize]}px`; + } + hide() { + if (this._isTransitioning || !this._isShown()) { + return; + } + const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6); + if (startEvent.defaultPrevented) { + return; + } + const dimension = this._getDimension(); + this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`; + reflow(this._element); + this._element.classList.add(CLASS_NAME_COLLAPSING); + this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + for (const trigger of this._triggerArray) { + const element = SelectorEngine.getElementFromSelector(trigger); + if (element && !this._isShown(element)) { + this._addAriaAndCollapsedClass([trigger], false); + } + } + this._isTransitioning = true; + const complete = () => { + this._isTransitioning = false; + this._element.classList.remove(CLASS_NAME_COLLAPSING); + this._element.classList.add(CLASS_NAME_COLLAPSE); + EventHandler.trigger(this._element, EVENT_HIDDEN$6); + }; + this._element.style[dimension] = ''; + this._queueCallback(complete, this._element, true); + } + _isShown(element = this._element) { + return element.classList.contains(CLASS_NAME_SHOW$7); + } + + // Private + _configAfterMerge(config) { + config.toggle = Boolean(config.toggle); // Coerce string values + config.parent = getElement(config.parent); + return config; + } + _getDimension() { + return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT; + } + _initializeChildren() { + if (!this._config.parent) { + return; + } + const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4); + for (const element of children) { + const selected = SelectorEngine.getElementFromSelector(element); + if (selected) { + this._addAriaAndCollapsedClass([element], this._isShown(selected)); + } + } + } + _getFirstLevelChildren(selector) { + const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); + // remove children if greater depth + return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element)); + } + _addAriaAndCollapsedClass(triggerArray, isOpen) { + if (!triggerArray.length) { + return; + } + for (const element of triggerArray) { + element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen); + element.setAttribute('aria-expanded', isOpen); + } + } + + // Static + static jQueryInterface(config) { + const _config = {}; + if (typeof config === 'string' && /show|hide/.test(config)) { + _config.toggle = false; + } + return this.each(function () { + const data = Collapse.getOrCreateInstance(this, _config); + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) { + // preventDefault only for elements (which change the URL) not inside the collapsible element + if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') { + event.preventDefault(); + } + for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) { + Collapse.getOrCreateInstance(element, { + toggle: false + }).toggle(); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Collapse); + + var top = 'top'; + var bottom = 'bottom'; + var right = 'right'; + var left = 'left'; + var auto = 'auto'; + var basePlacements = [top, bottom, right, left]; + var start = 'start'; + var end = 'end'; + var clippingParents = 'clippingParents'; + var viewport = 'viewport'; + var popper = 'popper'; + var reference = 'reference'; + var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) { + return acc.concat([placement + "-" + start, placement + "-" + end]); + }, []); + var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) { + return acc.concat([placement, placement + "-" + start, placement + "-" + end]); + }, []); // modifiers that need to read the DOM + + var beforeRead = 'beforeRead'; + var read = 'read'; + var afterRead = 'afterRead'; // pure-logic modifiers + + var beforeMain = 'beforeMain'; + var main = 'main'; + var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state) + + var beforeWrite = 'beforeWrite'; + var write = 'write'; + var afterWrite = 'afterWrite'; + var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite]; + + function getNodeName(element) { + return element ? (element.nodeName || '').toLowerCase() : null; + } + + function getWindow(node) { + if (node == null) { + return window; + } + + if (node.toString() !== '[object Window]') { + var ownerDocument = node.ownerDocument; + return ownerDocument ? ownerDocument.defaultView || window : window; + } + + return node; + } + + function isElement(node) { + var OwnElement = getWindow(node).Element; + return node instanceof OwnElement || node instanceof Element; + } + + function isHTMLElement(node) { + var OwnElement = getWindow(node).HTMLElement; + return node instanceof OwnElement || node instanceof HTMLElement; + } + + function isShadowRoot(node) { + // IE 11 has no ShadowRoot + if (typeof ShadowRoot === 'undefined') { + return false; + } + + var OwnElement = getWindow(node).ShadowRoot; + return node instanceof OwnElement || node instanceof ShadowRoot; + } + + // and applies them to the HTMLElements such as popper and arrow + + function applyStyles(_ref) { + var state = _ref.state; + Object.keys(state.elements).forEach(function (name) { + var style = state.styles[name] || {}; + var attributes = state.attributes[name] || {}; + var element = state.elements[name]; // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } // Flow doesn't support to extend this property, but it's the most + // effective way to apply styles to an HTMLElement + // $FlowFixMe[cannot-write] + + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (name) { + var value = attributes[name]; + + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value === true ? '' : value); + } + }); + }); + } + + function effect$2(_ref2) { + var state = _ref2.state; + var initialStyles = { + popper: { + position: state.options.strategy, + left: '0', + top: '0', + margin: '0' + }, + arrow: { + position: 'absolute' + }, + reference: {} + }; + Object.assign(state.elements.popper.style, initialStyles.popper); + state.styles = initialStyles; + + if (state.elements.arrow) { + Object.assign(state.elements.arrow.style, initialStyles.arrow); + } + + return function () { + Object.keys(state.elements).forEach(function (name) { + var element = state.elements[name]; + var attributes = state.attributes[name] || {}; + var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them + + var style = styleProperties.reduce(function (style, property) { + style[property] = ''; + return style; + }, {}); // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (attribute) { + element.removeAttribute(attribute); + }); + }); + }; + } // eslint-disable-next-line import/no-unused-modules + + + const applyStyles$1 = { + name: 'applyStyles', + enabled: true, + phase: 'write', + fn: applyStyles, + effect: effect$2, + requires: ['computeStyles'] + }; + + function getBasePlacement(placement) { + return placement.split('-')[0]; + } + + var max = Math.max; + var min = Math.min; + var round = Math.round; + + function getUAString() { + var uaData = navigator.userAgentData; + + if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) { + return uaData.brands.map(function (item) { + return item.brand + "/" + item.version; + }).join(' '); + } + + return navigator.userAgent; + } + + function isLayoutViewport() { + return !/^((?!chrome|android).)*safari/i.test(getUAString()); + } + + function getBoundingClientRect(element, includeScale, isFixedStrategy) { + if (includeScale === void 0) { + includeScale = false; + } + + if (isFixedStrategy === void 0) { + isFixedStrategy = false; + } + + var clientRect = element.getBoundingClientRect(); + var scaleX = 1; + var scaleY = 1; + + if (includeScale && isHTMLElement(element)) { + scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1; + scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1; + } + + var _ref = isElement(element) ? getWindow(element) : window, + visualViewport = _ref.visualViewport; + + var addVisualOffsets = !isLayoutViewport() && isFixedStrategy; + var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX; + var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY; + var width = clientRect.width / scaleX; + var height = clientRect.height / scaleY; + return { + width: width, + height: height, + top: y, + right: x + width, + bottom: y + height, + left: x, + x: x, + y: y + }; + } + + // means it doesn't take into account transforms. + + function getLayoutRect(element) { + var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed. + // Fixes https://github.com/popperjs/popper-core/issues/1223 + + var width = element.offsetWidth; + var height = element.offsetHeight; + + if (Math.abs(clientRect.width - width) <= 1) { + width = clientRect.width; + } + + if (Math.abs(clientRect.height - height) <= 1) { + height = clientRect.height; + } + + return { + x: element.offsetLeft, + y: element.offsetTop, + width: width, + height: height + }; + } + + function contains(parent, child) { + var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method + + if (parent.contains(child)) { + return true; + } // then fallback to custom implementation with Shadow DOM support + else if (rootNode && isShadowRoot(rootNode)) { + var next = child; + + do { + if (next && parent.isSameNode(next)) { + return true; + } // $FlowFixMe[prop-missing]: need a better way to handle this... + + + next = next.parentNode || next.host; + } while (next); + } // Give up, the result is false + + + return false; + } + + function getComputedStyle$1(element) { + return getWindow(element).getComputedStyle(element); + } + + function isTableElement(element) { + return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0; + } + + function getDocumentElement(element) { + // $FlowFixMe[incompatible-return]: assume body is always available + return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing] + element.document) || window.document).documentElement; + } + + function getParentNode(element) { + if (getNodeName(element) === 'html') { + return element; + } + + return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle + // $FlowFixMe[incompatible-return] + // $FlowFixMe[prop-missing] + element.assignedSlot || // step into the shadow DOM of the parent of a slotted node + element.parentNode || ( // DOM Element detected + isShadowRoot(element) ? element.host : null) || // ShadowRoot detected + // $FlowFixMe[incompatible-call]: HTMLElement is a Node + getDocumentElement(element) // fallback + + ); + } + + function getTrueOffsetParent(element) { + if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837 + getComputedStyle$1(element).position === 'fixed') { + return null; + } + + return element.offsetParent; + } // `.offsetParent` reports `null` for fixed elements, while absolute elements + // return the containing block + + + function getContainingBlock(element) { + var isFirefox = /firefox/i.test(getUAString()); + var isIE = /Trident/i.test(getUAString()); + + if (isIE && isHTMLElement(element)) { + // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport + var elementCss = getComputedStyle$1(element); + + if (elementCss.position === 'fixed') { + return null; + } + } + + var currentNode = getParentNode(element); + + if (isShadowRoot(currentNode)) { + currentNode = currentNode.host; + } + + while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) { + var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that + // create a containing block. + // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block + + if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') { + return currentNode; + } else { + currentNode = currentNode.parentNode; + } + } + + return null; + } // Gets the closest ancestor positioned element. Handles some edge cases, + // such as table ancestors and cross browser bugs. + + + function getOffsetParent(element) { + var window = getWindow(element); + var offsetParent = getTrueOffsetParent(element); + + while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') { + offsetParent = getTrueOffsetParent(offsetParent); + } + + if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) { + return window; + } + + return offsetParent || getContainingBlock(element) || window; + } + + function getMainAxisFromPlacement(placement) { + return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y'; + } + + function within(min$1, value, max$1) { + return max(min$1, min(value, max$1)); + } + function withinMaxClamp(min, value, max) { + var v = within(min, value, max); + return v > max ? max : v; + } + + function getFreshSideObject() { + return { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + + function mergePaddingObject(paddingObject) { + return Object.assign({}, getFreshSideObject(), paddingObject); + } + + function expandToHashMap(value, keys) { + return keys.reduce(function (hashMap, key) { + hashMap[key] = value; + return hashMap; + }, {}); + } + + var toPaddingObject = function toPaddingObject(padding, state) { + padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, { + placement: state.placement + })) : padding; + return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); + }; + + function arrow(_ref) { + var _state$modifiersData$; + + var state = _ref.state, + name = _ref.name, + options = _ref.options; + var arrowElement = state.elements.arrow; + var popperOffsets = state.modifiersData.popperOffsets; + var basePlacement = getBasePlacement(state.placement); + var axis = getMainAxisFromPlacement(basePlacement); + var isVertical = [left, right].indexOf(basePlacement) >= 0; + var len = isVertical ? 'height' : 'width'; + + if (!arrowElement || !popperOffsets) { + return; + } + + var paddingObject = toPaddingObject(options.padding, state); + var arrowRect = getLayoutRect(arrowElement); + var minProp = axis === 'y' ? top : left; + var maxProp = axis === 'y' ? bottom : right; + var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len]; + var startDiff = popperOffsets[axis] - state.rects.reference[axis]; + var arrowOffsetParent = getOffsetParent(arrowElement); + var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0; + var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is + // outside of the popper bounds + + var min = paddingObject[minProp]; + var max = clientSize - arrowRect[len] - paddingObject[maxProp]; + var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference; + var offset = within(min, center, max); // Prevents breaking syntax highlighting... + + var axisProp = axis; + state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$); + } + + function effect$1(_ref2) { + var state = _ref2.state, + options = _ref2.options; + var _options$element = options.element, + arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element; + + if (arrowElement == null) { + return; + } // CSS selector + + + if (typeof arrowElement === 'string') { + arrowElement = state.elements.popper.querySelector(arrowElement); + + if (!arrowElement) { + return; + } + } + + if (!contains(state.elements.popper, arrowElement)) { + return; + } + + state.elements.arrow = arrowElement; + } // eslint-disable-next-line import/no-unused-modules + + + const arrow$1 = { + name: 'arrow', + enabled: true, + phase: 'main', + fn: arrow, + effect: effect$1, + requires: ['popperOffsets'], + requiresIfExists: ['preventOverflow'] + }; + + function getVariation(placement) { + return placement.split('-')[1]; + } + + var unsetSides = { + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto' + }; // Round the offsets to the nearest suitable subpixel based on the DPR. + // Zooming can change the DPR, but it seems to report a value that will + // cleanly divide the values into the appropriate subpixels. + + function roundOffsetsByDPR(_ref, win) { + var x = _ref.x, + y = _ref.y; + var dpr = win.devicePixelRatio || 1; + return { + x: round(x * dpr) / dpr || 0, + y: round(y * dpr) / dpr || 0 + }; + } + + function mapToStyles(_ref2) { + var _Object$assign2; + + var popper = _ref2.popper, + popperRect = _ref2.popperRect, + placement = _ref2.placement, + variation = _ref2.variation, + offsets = _ref2.offsets, + position = _ref2.position, + gpuAcceleration = _ref2.gpuAcceleration, + adaptive = _ref2.adaptive, + roundOffsets = _ref2.roundOffsets, + isFixed = _ref2.isFixed; + var _offsets$x = offsets.x, + x = _offsets$x === void 0 ? 0 : _offsets$x, + _offsets$y = offsets.y, + y = _offsets$y === void 0 ? 0 : _offsets$y; + + var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({ + x: x, + y: y + }) : { + x: x, + y: y + }; + + x = _ref3.x; + y = _ref3.y; + var hasX = offsets.hasOwnProperty('x'); + var hasY = offsets.hasOwnProperty('y'); + var sideX = left; + var sideY = top; + var win = window; + + if (adaptive) { + var offsetParent = getOffsetParent(popper); + var heightProp = 'clientHeight'; + var widthProp = 'clientWidth'; + + if (offsetParent === getWindow(popper)) { + offsetParent = getDocumentElement(popper); + + if (getComputedStyle$1(offsetParent).position !== 'static' && position === 'absolute') { + heightProp = 'scrollHeight'; + widthProp = 'scrollWidth'; + } + } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it + + + offsetParent = offsetParent; + + if (placement === top || (placement === left || placement === right) && variation === end) { + sideY = bottom; + var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing] + offsetParent[heightProp]; + y -= offsetY - popperRect.height; + y *= gpuAcceleration ? 1 : -1; + } + + if (placement === left || (placement === top || placement === bottom) && variation === end) { + sideX = right; + var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing] + offsetParent[widthProp]; + x -= offsetX - popperRect.width; + x *= gpuAcceleration ? 1 : -1; + } + } + + var commonStyles = Object.assign({ + position: position + }, adaptive && unsetSides); + + var _ref4 = roundOffsets === true ? roundOffsetsByDPR({ + x: x, + y: y + }, getWindow(popper)) : { + x: x, + y: y + }; + + x = _ref4.x; + y = _ref4.y; + + if (gpuAcceleration) { + var _Object$assign; + + return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign)); + } + + return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2)); + } + + function computeStyles(_ref5) { + var state = _ref5.state, + options = _ref5.options; + var _options$gpuAccelerat = options.gpuAcceleration, + gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat, + _options$adaptive = options.adaptive, + adaptive = _options$adaptive === void 0 ? true : _options$adaptive, + _options$roundOffsets = options.roundOffsets, + roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets; + var commonStyles = { + placement: getBasePlacement(state.placement), + variation: getVariation(state.placement), + popper: state.elements.popper, + popperRect: state.rects.popper, + gpuAcceleration: gpuAcceleration, + isFixed: state.options.strategy === 'fixed' + }; + + if (state.modifiersData.popperOffsets != null) { + state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, { + offsets: state.modifiersData.popperOffsets, + position: state.options.strategy, + adaptive: adaptive, + roundOffsets: roundOffsets + }))); + } + + if (state.modifiersData.arrow != null) { + state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, { + offsets: state.modifiersData.arrow, + position: 'absolute', + adaptive: false, + roundOffsets: roundOffsets + }))); + } + + state.attributes.popper = Object.assign({}, state.attributes.popper, { + 'data-popper-placement': state.placement + }); + } // eslint-disable-next-line import/no-unused-modules + + + const computeStyles$1 = { + name: 'computeStyles', + enabled: true, + phase: 'beforeWrite', + fn: computeStyles, + data: {} + }; + + var passive = { + passive: true + }; + + function effect(_ref) { + var state = _ref.state, + instance = _ref.instance, + options = _ref.options; + var _options$scroll = options.scroll, + scroll = _options$scroll === void 0 ? true : _options$scroll, + _options$resize = options.resize, + resize = _options$resize === void 0 ? true : _options$resize; + var window = getWindow(state.elements.popper); + var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper); + + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.addEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.addEventListener('resize', instance.update, passive); + } + + return function () { + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.removeEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.removeEventListener('resize', instance.update, passive); + } + }; + } // eslint-disable-next-line import/no-unused-modules + + + const eventListeners = { + name: 'eventListeners', + enabled: true, + phase: 'write', + fn: function fn() {}, + effect: effect, + data: {} + }; + + var hash$1 = { + left: 'right', + right: 'left', + bottom: 'top', + top: 'bottom' + }; + function getOppositePlacement(placement) { + return placement.replace(/left|right|bottom|top/g, function (matched) { + return hash$1[matched]; + }); + } + + var hash = { + start: 'end', + end: 'start' + }; + function getOppositeVariationPlacement(placement) { + return placement.replace(/start|end/g, function (matched) { + return hash[matched]; + }); + } + + function getWindowScroll(node) { + var win = getWindow(node); + var scrollLeft = win.pageXOffset; + var scrollTop = win.pageYOffset; + return { + scrollLeft: scrollLeft, + scrollTop: scrollTop + }; + } + + function getWindowScrollBarX(element) { + // If has a CSS width greater than the viewport, then this will be + // incorrect for RTL. + // Popper 1 is broken in this case and never had a bug report so let's assume + // it's not an issue. I don't think anyone ever specifies width on + // anyway. + // Browsers where the left scrollbar doesn't cause an issue report `0` for + // this (e.g. Edge 2019, IE11, Safari) + return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft; + } + + function getViewportRect(element, strategy) { + var win = getWindow(element); + var html = getDocumentElement(element); + var visualViewport = win.visualViewport; + var width = html.clientWidth; + var height = html.clientHeight; + var x = 0; + var y = 0; + + if (visualViewport) { + width = visualViewport.width; + height = visualViewport.height; + var layoutViewport = isLayoutViewport(); + + if (layoutViewport || !layoutViewport && strategy === 'fixed') { + x = visualViewport.offsetLeft; + y = visualViewport.offsetTop; + } + } + + return { + width: width, + height: height, + x: x + getWindowScrollBarX(element), + y: y + }; + } + + // of the `` and `` rect bounds if horizontally scrollable + + function getDocumentRect(element) { + var _element$ownerDocumen; + + var html = getDocumentElement(element); + var winScroll = getWindowScroll(element); + var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body; + var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0); + var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0); + var x = -winScroll.scrollLeft + getWindowScrollBarX(element); + var y = -winScroll.scrollTop; + + if (getComputedStyle$1(body || html).direction === 'rtl') { + x += max(html.clientWidth, body ? body.clientWidth : 0) - width; + } + + return { + width: width, + height: height, + x: x, + y: y + }; + } + + function isScrollParent(element) { + // Firefox wants us to check `-x` and `-y` variations as well + var _getComputedStyle = getComputedStyle$1(element), + overflow = _getComputedStyle.overflow, + overflowX = _getComputedStyle.overflowX, + overflowY = _getComputedStyle.overflowY; + + return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX); + } + + function getScrollParent(node) { + if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) { + // $FlowFixMe[incompatible-return]: assume body is always available + return node.ownerDocument.body; + } + + if (isHTMLElement(node) && isScrollParent(node)) { + return node; + } + + return getScrollParent(getParentNode(node)); + } + + /* + given a DOM element, return the list of all scroll parents, up the list of ancesors + until we get to the top window object. This list is what we attach scroll listeners + to, because if any of these parent elements scroll, we'll need to re-calculate the + reference element's position. + */ + + function listScrollParents(element, list) { + var _element$ownerDocumen; + + if (list === void 0) { + list = []; + } + + var scrollParent = getScrollParent(element); + var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body); + var win = getWindow(scrollParent); + var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent; + var updatedList = list.concat(target); + return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here + updatedList.concat(listScrollParents(getParentNode(target))); + } + + function rectToClientRect(rect) { + return Object.assign({}, rect, { + left: rect.x, + top: rect.y, + right: rect.x + rect.width, + bottom: rect.y + rect.height + }); + } + + function getInnerBoundingClientRect(element, strategy) { + var rect = getBoundingClientRect(element, false, strategy === 'fixed'); + rect.top = rect.top + element.clientTop; + rect.left = rect.left + element.clientLeft; + rect.bottom = rect.top + element.clientHeight; + rect.right = rect.left + element.clientWidth; + rect.width = element.clientWidth; + rect.height = element.clientHeight; + rect.x = rect.left; + rect.y = rect.top; + return rect; + } + + function getClientRectFromMixedType(element, clippingParent, strategy) { + return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element))); + } // A "clipping parent" is an overflowable container with the characteristic of + // clipping (or hiding) overflowing elements with a position different from + // `initial` + + + function getClippingParents(element) { + var clippingParents = listScrollParents(getParentNode(element)); + var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0; + var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element; + + if (!isElement(clipperElement)) { + return []; + } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414 + + + return clippingParents.filter(function (clippingParent) { + return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body'; + }); + } // Gets the maximum area that the element is visible in due to any number of + // clipping parents + + + function getClippingRect(element, boundary, rootBoundary, strategy) { + var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary); + var clippingParents = [].concat(mainClippingParents, [rootBoundary]); + var firstClippingParent = clippingParents[0]; + var clippingRect = clippingParents.reduce(function (accRect, clippingParent) { + var rect = getClientRectFromMixedType(element, clippingParent, strategy); + accRect.top = max(rect.top, accRect.top); + accRect.right = min(rect.right, accRect.right); + accRect.bottom = min(rect.bottom, accRect.bottom); + accRect.left = max(rect.left, accRect.left); + return accRect; + }, getClientRectFromMixedType(element, firstClippingParent, strategy)); + clippingRect.width = clippingRect.right - clippingRect.left; + clippingRect.height = clippingRect.bottom - clippingRect.top; + clippingRect.x = clippingRect.left; + clippingRect.y = clippingRect.top; + return clippingRect; + } + + function computeOffsets(_ref) { + var reference = _ref.reference, + element = _ref.element, + placement = _ref.placement; + var basePlacement = placement ? getBasePlacement(placement) : null; + var variation = placement ? getVariation(placement) : null; + var commonX = reference.x + reference.width / 2 - element.width / 2; + var commonY = reference.y + reference.height / 2 - element.height / 2; + var offsets; + + switch (basePlacement) { + case top: + offsets = { + x: commonX, + y: reference.y - element.height + }; + break; + + case bottom: + offsets = { + x: commonX, + y: reference.y + reference.height + }; + break; + + case right: + offsets = { + x: reference.x + reference.width, + y: commonY + }; + break; + + case left: + offsets = { + x: reference.x - element.width, + y: commonY + }; + break; + + default: + offsets = { + x: reference.x, + y: reference.y + }; + } + + var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null; + + if (mainAxis != null) { + var len = mainAxis === 'y' ? 'height' : 'width'; + + switch (variation) { + case start: + offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2); + break; + + case end: + offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2); + break; + } + } + + return offsets; + } + + function detectOverflow(state, options) { + if (options === void 0) { + options = {}; + } + + var _options = options, + _options$placement = _options.placement, + placement = _options$placement === void 0 ? state.placement : _options$placement, + _options$strategy = _options.strategy, + strategy = _options$strategy === void 0 ? state.strategy : _options$strategy, + _options$boundary = _options.boundary, + boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, + _options$rootBoundary = _options.rootBoundary, + rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, + _options$elementConte = _options.elementContext, + elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, + _options$altBoundary = _options.altBoundary, + altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary, + _options$padding = _options.padding, + padding = _options$padding === void 0 ? 0 : _options$padding; + var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); + var altContext = elementContext === popper ? reference : popper; + var popperRect = state.rects.popper; + var element = state.elements[altBoundary ? altContext : elementContext]; + var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy); + var referenceClientRect = getBoundingClientRect(state.elements.reference); + var popperOffsets = computeOffsets({ + reference: referenceClientRect, + element: popperRect, + strategy: 'absolute', + placement: placement + }); + var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets)); + var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect + // 0 or negative = within the clipping rect + + var overflowOffsets = { + top: clippingClientRect.top - elementClientRect.top + paddingObject.top, + bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom, + left: clippingClientRect.left - elementClientRect.left + paddingObject.left, + right: elementClientRect.right - clippingClientRect.right + paddingObject.right + }; + var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element + + if (elementContext === popper && offsetData) { + var offset = offsetData[placement]; + Object.keys(overflowOffsets).forEach(function (key) { + var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1; + var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x'; + overflowOffsets[key] += offset[axis] * multiply; + }); + } + + return overflowOffsets; + } + + function computeAutoPlacement(state, options) { + if (options === void 0) { + options = {}; + } + + var _options = options, + placement = _options.placement, + boundary = _options.boundary, + rootBoundary = _options.rootBoundary, + padding = _options.padding, + flipVariations = _options.flipVariations, + _options$allowedAutoP = _options.allowedAutoPlacements, + allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP; + var variation = getVariation(placement); + var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) { + return getVariation(placement) === variation; + }) : basePlacements; + var allowedPlacements = placements$1.filter(function (placement) { + return allowedAutoPlacements.indexOf(placement) >= 0; + }); + + if (allowedPlacements.length === 0) { + allowedPlacements = placements$1; + } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions... + + + var overflows = allowedPlacements.reduce(function (acc, placement) { + acc[placement] = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding + })[getBasePlacement(placement)]; + return acc; + }, {}); + return Object.keys(overflows).sort(function (a, b) { + return overflows[a] - overflows[b]; + }); + } + + function getExpandedFallbackPlacements(placement) { + if (getBasePlacement(placement) === auto) { + return []; + } + + var oppositePlacement = getOppositePlacement(placement); + return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)]; + } + + function flip(_ref) { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + + if (state.modifiersData[name]._skip) { + return; + } + + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis, + specifiedFallbackPlacements = options.fallbackPlacements, + padding = options.padding, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + _options$flipVariatio = options.flipVariations, + flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio, + allowedAutoPlacements = options.allowedAutoPlacements; + var preferredPlacement = state.options.placement; + var basePlacement = getBasePlacement(preferredPlacement); + var isBasePlacement = basePlacement === preferredPlacement; + var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement)); + var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) { + return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + flipVariations: flipVariations, + allowedAutoPlacements: allowedAutoPlacements + }) : placement); + }, []); + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var checksMap = new Map(); + var makeFallbackChecks = true; + var firstFittingPlacement = placements[0]; + + for (var i = 0; i < placements.length; i++) { + var placement = placements[i]; + + var _basePlacement = getBasePlacement(placement); + + var isStartVariation = getVariation(placement) === start; + var isVertical = [top, bottom].indexOf(_basePlacement) >= 0; + var len = isVertical ? 'width' : 'height'; + var overflow = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + altBoundary: altBoundary, + padding: padding + }); + var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top; + + if (referenceRect[len] > popperRect[len]) { + mainVariationSide = getOppositePlacement(mainVariationSide); + } + + var altVariationSide = getOppositePlacement(mainVariationSide); + var checks = []; + + if (checkMainAxis) { + checks.push(overflow[_basePlacement] <= 0); + } + + if (checkAltAxis) { + checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0); + } + + if (checks.every(function (check) { + return check; + })) { + firstFittingPlacement = placement; + makeFallbackChecks = false; + break; + } + + checksMap.set(placement, checks); + } + + if (makeFallbackChecks) { + // `2` may be desired in some cases – research later + var numberOfChecks = flipVariations ? 3 : 1; + + var _loop = function _loop(_i) { + var fittingPlacement = placements.find(function (placement) { + var checks = checksMap.get(placement); + + if (checks) { + return checks.slice(0, _i).every(function (check) { + return check; + }); + } + }); + + if (fittingPlacement) { + firstFittingPlacement = fittingPlacement; + return "break"; + } + }; + + for (var _i = numberOfChecks; _i > 0; _i--) { + var _ret = _loop(_i); + + if (_ret === "break") break; + } + } + + if (state.placement !== firstFittingPlacement) { + state.modifiersData[name]._skip = true; + state.placement = firstFittingPlacement; + state.reset = true; + } + } // eslint-disable-next-line import/no-unused-modules + + + const flip$1 = { + name: 'flip', + enabled: true, + phase: 'main', + fn: flip, + requiresIfExists: ['offset'], + data: { + _skip: false + } + }; + + function getSideOffsets(overflow, rect, preventedOffsets) { + if (preventedOffsets === void 0) { + preventedOffsets = { + x: 0, + y: 0 + }; + } + + return { + top: overflow.top - rect.height - preventedOffsets.y, + right: overflow.right - rect.width + preventedOffsets.x, + bottom: overflow.bottom - rect.height + preventedOffsets.y, + left: overflow.left - rect.width - preventedOffsets.x + }; + } + + function isAnySideFullyClipped(overflow) { + return [top, right, bottom, left].some(function (side) { + return overflow[side] >= 0; + }); + } + + function hide(_ref) { + var state = _ref.state, + name = _ref.name; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var preventedOffsets = state.modifiersData.preventOverflow; + var referenceOverflow = detectOverflow(state, { + elementContext: 'reference' + }); + var popperAltOverflow = detectOverflow(state, { + altBoundary: true + }); + var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect); + var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets); + var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets); + var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets); + state.modifiersData[name] = { + referenceClippingOffsets: referenceClippingOffsets, + popperEscapeOffsets: popperEscapeOffsets, + isReferenceHidden: isReferenceHidden, + hasPopperEscaped: hasPopperEscaped + }; + state.attributes.popper = Object.assign({}, state.attributes.popper, { + 'data-popper-reference-hidden': isReferenceHidden, + 'data-popper-escaped': hasPopperEscaped + }); + } // eslint-disable-next-line import/no-unused-modules + + + const hide$1 = { + name: 'hide', + enabled: true, + phase: 'main', + requiresIfExists: ['preventOverflow'], + fn: hide + }; + + function distanceAndSkiddingToXY(placement, rects, offset) { + var basePlacement = getBasePlacement(placement); + var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1; + + var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, { + placement: placement + })) : offset, + skidding = _ref[0], + distance = _ref[1]; + + skidding = skidding || 0; + distance = (distance || 0) * invertDistance; + return [left, right].indexOf(basePlacement) >= 0 ? { + x: distance, + y: skidding + } : { + x: skidding, + y: distance + }; + } + + function offset(_ref2) { + var state = _ref2.state, + options = _ref2.options, + name = _ref2.name; + var _options$offset = options.offset, + offset = _options$offset === void 0 ? [0, 0] : _options$offset; + var data = placements.reduce(function (acc, placement) { + acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset); + return acc; + }, {}); + var _data$state$placement = data[state.placement], + x = _data$state$placement.x, + y = _data$state$placement.y; + + if (state.modifiersData.popperOffsets != null) { + state.modifiersData.popperOffsets.x += x; + state.modifiersData.popperOffsets.y += y; + } + + state.modifiersData[name] = data; + } // eslint-disable-next-line import/no-unused-modules + + + const offset$1 = { + name: 'offset', + enabled: true, + phase: 'main', + requires: ['popperOffsets'], + fn: offset + }; + + function popperOffsets(_ref) { + var state = _ref.state, + name = _ref.name; + // Offsets are the actual position the popper needs to have to be + // properly positioned near its reference element + // This is the most basic placement, and will be adjusted by + // the modifiers in the next step + state.modifiersData[name] = computeOffsets({ + reference: state.rects.reference, + element: state.rects.popper, + strategy: 'absolute', + placement: state.placement + }); + } // eslint-disable-next-line import/no-unused-modules + + + const popperOffsets$1 = { + name: 'popperOffsets', + enabled: true, + phase: 'read', + fn: popperOffsets, + data: {} + }; + + function getAltAxis(axis) { + return axis === 'x' ? 'y' : 'x'; + } + + function preventOverflow(_ref) { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + padding = options.padding, + _options$tether = options.tether, + tether = _options$tether === void 0 ? true : _options$tether, + _options$tetherOffset = options.tetherOffset, + tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset; + var overflow = detectOverflow(state, { + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + altBoundary: altBoundary + }); + var basePlacement = getBasePlacement(state.placement); + var variation = getVariation(state.placement); + var isBasePlacement = !variation; + var mainAxis = getMainAxisFromPlacement(basePlacement); + var altAxis = getAltAxis(mainAxis); + var popperOffsets = state.modifiersData.popperOffsets; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, { + placement: state.placement + })) : tetherOffset; + var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? { + mainAxis: tetherOffsetValue, + altAxis: tetherOffsetValue + } : Object.assign({ + mainAxis: 0, + altAxis: 0 + }, tetherOffsetValue); + var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null; + var data = { + x: 0, + y: 0 + }; + + if (!popperOffsets) { + return; + } + + if (checkMainAxis) { + var _offsetModifierState$; + + var mainSide = mainAxis === 'y' ? top : left; + var altSide = mainAxis === 'y' ? bottom : right; + var len = mainAxis === 'y' ? 'height' : 'width'; + var offset = popperOffsets[mainAxis]; + var min$1 = offset + overflow[mainSide]; + var max$1 = offset - overflow[altSide]; + var additive = tether ? -popperRect[len] / 2 : 0; + var minLen = variation === start ? referenceRect[len] : popperRect[len]; + var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go + // outside the reference bounds + + var arrowElement = state.elements.arrow; + var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : { + width: 0, + height: 0 + }; + var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject(); + var arrowPaddingMin = arrowPaddingObject[mainSide]; + var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want + // to include its full size in the calculation. If the reference is small + // and near the edge of a boundary, the popper can overflow even if the + // reference is not overflowing as well (e.g. virtual elements with no + // width or height) + + var arrowLen = within(0, referenceRect[len], arrowRect[len]); + var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis; + var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis; + var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow); + var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0; + var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0; + var tetherMin = offset + minOffset - offsetModifierValue - clientOffset; + var tetherMax = offset + maxOffset - offsetModifierValue; + var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1); + popperOffsets[mainAxis] = preventedOffset; + data[mainAxis] = preventedOffset - offset; + } + + if (checkAltAxis) { + var _offsetModifierState$2; + + var _mainSide = mainAxis === 'x' ? top : left; + + var _altSide = mainAxis === 'x' ? bottom : right; + + var _offset = popperOffsets[altAxis]; + + var _len = altAxis === 'y' ? 'height' : 'width'; + + var _min = _offset + overflow[_mainSide]; + + var _max = _offset - overflow[_altSide]; + + var isOriginSide = [top, left].indexOf(basePlacement) !== -1; + + var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0; + + var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis; + + var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max; + + var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max); + + popperOffsets[altAxis] = _preventedOffset; + data[altAxis] = _preventedOffset - _offset; + } + + state.modifiersData[name] = data; + } // eslint-disable-next-line import/no-unused-modules + + + const preventOverflow$1 = { + name: 'preventOverflow', + enabled: true, + phase: 'main', + fn: preventOverflow, + requiresIfExists: ['offset'] + }; + + function getHTMLElementScroll(element) { + return { + scrollLeft: element.scrollLeft, + scrollTop: element.scrollTop + }; + } + + function getNodeScroll(node) { + if (node === getWindow(node) || !isHTMLElement(node)) { + return getWindowScroll(node); + } else { + return getHTMLElementScroll(node); + } + } + + function isElementScaled(element) { + var rect = element.getBoundingClientRect(); + var scaleX = round(rect.width) / element.offsetWidth || 1; + var scaleY = round(rect.height) / element.offsetHeight || 1; + return scaleX !== 1 || scaleY !== 1; + } // Returns the composite rect of an element relative to its offsetParent. + // Composite means it takes into account transforms as well as layout. + + + function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) { + if (isFixed === void 0) { + isFixed = false; + } + + var isOffsetParentAnElement = isHTMLElement(offsetParent); + var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent); + var documentElement = getDocumentElement(offsetParent); + var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed); + var scroll = { + scrollLeft: 0, + scrollTop: 0 + }; + var offsets = { + x: 0, + y: 0 + }; + + if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { + if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078 + isScrollParent(documentElement)) { + scroll = getNodeScroll(offsetParent); + } + + if (isHTMLElement(offsetParent)) { + offsets = getBoundingClientRect(offsetParent, true); + offsets.x += offsetParent.clientLeft; + offsets.y += offsetParent.clientTop; + } else if (documentElement) { + offsets.x = getWindowScrollBarX(documentElement); + } + } + + return { + x: rect.left + scroll.scrollLeft - offsets.x, + y: rect.top + scroll.scrollTop - offsets.y, + width: rect.width, + height: rect.height + }; + } + + function order(modifiers) { + var map = new Map(); + var visited = new Set(); + var result = []; + modifiers.forEach(function (modifier) { + map.set(modifier.name, modifier); + }); // On visiting object, check for its dependencies and visit them recursively + + function sort(modifier) { + visited.add(modifier.name); + var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []); + requires.forEach(function (dep) { + if (!visited.has(dep)) { + var depModifier = map.get(dep); + + if (depModifier) { + sort(depModifier); + } + } + }); + result.push(modifier); + } + + modifiers.forEach(function (modifier) { + if (!visited.has(modifier.name)) { + // check for visited object + sort(modifier); + } + }); + return result; + } + + function orderModifiers(modifiers) { + // order based on dependencies + var orderedModifiers = order(modifiers); // order based on phase + + return modifierPhases.reduce(function (acc, phase) { + return acc.concat(orderedModifiers.filter(function (modifier) { + return modifier.phase === phase; + })); + }, []); + } + + function debounce(fn) { + var pending; + return function () { + if (!pending) { + pending = new Promise(function (resolve) { + Promise.resolve().then(function () { + pending = undefined; + resolve(fn()); + }); + }); + } + + return pending; + }; + } + + function mergeByName(modifiers) { + var merged = modifiers.reduce(function (merged, current) { + var existing = merged[current.name]; + merged[current.name] = existing ? Object.assign({}, existing, current, { + options: Object.assign({}, existing.options, current.options), + data: Object.assign({}, existing.data, current.data) + }) : current; + return merged; + }, {}); // IE11 does not support Object.values + + return Object.keys(merged).map(function (key) { + return merged[key]; + }); + } + + var DEFAULT_OPTIONS = { + placement: 'bottom', + modifiers: [], + strategy: 'absolute' + }; + + function areValidElements() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return !args.some(function (element) { + return !(element && typeof element.getBoundingClientRect === 'function'); + }); + } + + function popperGenerator(generatorOptions) { + if (generatorOptions === void 0) { + generatorOptions = {}; + } + + var _generatorOptions = generatorOptions, + _generatorOptions$def = _generatorOptions.defaultModifiers, + defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def, + _generatorOptions$def2 = _generatorOptions.defaultOptions, + defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2; + return function createPopper(reference, popper, options) { + if (options === void 0) { + options = defaultOptions; + } + + var state = { + placement: 'bottom', + orderedModifiers: [], + options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions), + modifiersData: {}, + elements: { + reference: reference, + popper: popper + }, + attributes: {}, + styles: {} + }; + var effectCleanupFns = []; + var isDestroyed = false; + var instance = { + state: state, + setOptions: function setOptions(setOptionsAction) { + var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction; + cleanupModifierEffects(); + state.options = Object.assign({}, defaultOptions, state.options, options); + state.scrollParents = { + reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [], + popper: listScrollParents(popper) + }; // Orders the modifiers based on their dependencies and `phase` + // properties + + var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers + + state.orderedModifiers = orderedModifiers.filter(function (m) { + return m.enabled; + }); + runModifierEffects(); + return instance.update(); + }, + // Sync update – it will always be executed, even if not necessary. This + // is useful for low frequency updates where sync behavior simplifies the + // logic. + // For high frequency updates (e.g. `resize` and `scroll` events), always + // prefer the async Popper#update method + forceUpdate: function forceUpdate() { + if (isDestroyed) { + return; + } + + var _state$elements = state.elements, + reference = _state$elements.reference, + popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements + // anymore + + if (!areValidElements(reference, popper)) { + return; + } // Store the reference and popper rects to be read by modifiers + + + state.rects = { + reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'), + popper: getLayoutRect(popper) + }; // Modifiers have the ability to reset the current update cycle. The + // most common use case for this is the `flip` modifier changing the + // placement, which then needs to re-run all the modifiers, because the + // logic was previously ran for the previous placement and is therefore + // stale/incorrect + + state.reset = false; + state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier + // is filled with the initial data specified by the modifier. This means + // it doesn't persist and is fresh on each update. + // To ensure persistent data, use `${name}#persistent` + + state.orderedModifiers.forEach(function (modifier) { + return state.modifiersData[modifier.name] = Object.assign({}, modifier.data); + }); + + for (var index = 0; index < state.orderedModifiers.length; index++) { + if (state.reset === true) { + state.reset = false; + index = -1; + continue; + } + + var _state$orderedModifie = state.orderedModifiers[index], + fn = _state$orderedModifie.fn, + _state$orderedModifie2 = _state$orderedModifie.options, + _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2, + name = _state$orderedModifie.name; + + if (typeof fn === 'function') { + state = fn({ + state: state, + options: _options, + name: name, + instance: instance + }) || state; + } + } + }, + // Async and optimistically optimized update – it will not be executed if + // not necessary (debounced to run at most once-per-tick) + update: debounce(function () { + return new Promise(function (resolve) { + instance.forceUpdate(); + resolve(state); + }); + }), + destroy: function destroy() { + cleanupModifierEffects(); + isDestroyed = true; + } + }; + + if (!areValidElements(reference, popper)) { + return instance; + } + + instance.setOptions(options).then(function (state) { + if (!isDestroyed && options.onFirstUpdate) { + options.onFirstUpdate(state); + } + }); // Modifiers have the ability to execute arbitrary code before the first + // update cycle runs. They will be executed in the same order as the update + // cycle. This is useful when a modifier adds some persistent data that + // other modifiers need to use, but the modifier is run after the dependent + // one. + + function runModifierEffects() { + state.orderedModifiers.forEach(function (_ref) { + var name = _ref.name, + _ref$options = _ref.options, + options = _ref$options === void 0 ? {} : _ref$options, + effect = _ref.effect; + + if (typeof effect === 'function') { + var cleanupFn = effect({ + state: state, + name: name, + instance: instance, + options: options + }); + + var noopFn = function noopFn() {}; + + effectCleanupFns.push(cleanupFn || noopFn); + } + }); + } + + function cleanupModifierEffects() { + effectCleanupFns.forEach(function (fn) { + return fn(); + }); + effectCleanupFns = []; + } + + return instance; + }; + } + var createPopper$2 = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules + + var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1]; + var createPopper$1 = /*#__PURE__*/popperGenerator({ + defaultModifiers: defaultModifiers$1 + }); // eslint-disable-next-line import/no-unused-modules + + var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1]; + var createPopper = /*#__PURE__*/popperGenerator({ + defaultModifiers: defaultModifiers + }); // eslint-disable-next-line import/no-unused-modules + + const Popper = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({ + __proto__: null, + afterMain, + afterRead, + afterWrite, + applyStyles: applyStyles$1, + arrow: arrow$1, + auto, + basePlacements, + beforeMain, + beforeRead, + beforeWrite, + bottom, + clippingParents, + computeStyles: computeStyles$1, + createPopper, + createPopperBase: createPopper$2, + createPopperLite: createPopper$1, + detectOverflow, + end, + eventListeners, + flip: flip$1, + hide: hide$1, + left, + main, + modifierPhases, + offset: offset$1, + placements, + popper, + popperGenerator, + popperOffsets: popperOffsets$1, + preventOverflow: preventOverflow$1, + read, + reference, + right, + start, + top, + variationPlacements, + viewport, + write + }, Symbol.toStringTag, { value: 'Module' })); + + /** + * -------------------------------------------------------------------------- + * Bootstrap dropdown.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$a = 'dropdown'; + const DATA_KEY$6 = 'bs.dropdown'; + const EVENT_KEY$6 = `.${DATA_KEY$6}`; + const DATA_API_KEY$3 = '.data-api'; + const ESCAPE_KEY$2 = 'Escape'; + const TAB_KEY$1 = 'Tab'; + const ARROW_UP_KEY$1 = 'ArrowUp'; + const ARROW_DOWN_KEY$1 = 'ArrowDown'; + const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button + + const EVENT_HIDE$5 = `hide${EVENT_KEY$6}`; + const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`; + const EVENT_SHOW$5 = `show${EVENT_KEY$6}`; + const EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`; + const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`; + const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`; + const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`; + const CLASS_NAME_SHOW$6 = 'show'; + const CLASS_NAME_DROPUP = 'dropup'; + const CLASS_NAME_DROPEND = 'dropend'; + const CLASS_NAME_DROPSTART = 'dropstart'; + const CLASS_NAME_DROPUP_CENTER = 'dropup-center'; + const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'; + const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)'; + const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`; + const SELECTOR_MENU = '.dropdown-menu'; + const SELECTOR_NAVBAR = '.navbar'; + const SELECTOR_NAVBAR_NAV = '.navbar-nav'; + const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'; + const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'; + const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'; + const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'; + const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'; + const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'; + const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'; + const PLACEMENT_TOPCENTER = 'top'; + const PLACEMENT_BOTTOMCENTER = 'bottom'; + const Default$9 = { + autoClose: true, + boundary: 'clippingParents', + display: 'dynamic', + offset: [0, 2], + popperConfig: null, + reference: 'toggle' + }; + const DefaultType$9 = { + autoClose: '(boolean|string)', + boundary: '(string|element)', + display: 'string', + offset: '(array|string|function)', + popperConfig: '(null|object|function)', + reference: '(string|element|object)' + }; + + /** + * Class definition + */ + + class Dropdown extends BaseComponent { + constructor(element, config) { + super(element, config); + this._popper = null; + this._parent = this._element.parentNode; // dropdown wrapper + // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/ + this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent); + this._inNavbar = this._detectNavbar(); + } + + // Getters + static get Default() { + return Default$9; + } + static get DefaultType() { + return DefaultType$9; + } + static get NAME() { + return NAME$a; + } + + // Public + toggle() { + return this._isShown() ? this.hide() : this.show(); + } + show() { + if (isDisabled(this._element) || this._isShown()) { + return; + } + const relatedTarget = { + relatedTarget: this._element + }; + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget); + if (showEvent.defaultPrevented) { + return; + } + this._createPopper(); + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) { + for (const element of [].concat(...document.body.children)) { + EventHandler.on(element, 'mouseover', noop); + } + } + this._element.focus(); + this._element.setAttribute('aria-expanded', true); + this._menu.classList.add(CLASS_NAME_SHOW$6); + this._element.classList.add(CLASS_NAME_SHOW$6); + EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget); + } + hide() { + if (isDisabled(this._element) || !this._isShown()) { + return; + } + const relatedTarget = { + relatedTarget: this._element + }; + this._completeHide(relatedTarget); + } + dispose() { + if (this._popper) { + this._popper.destroy(); + } + super.dispose(); + } + update() { + this._inNavbar = this._detectNavbar(); + if (this._popper) { + this._popper.update(); + } + } + + // Private + _completeHide(relatedTarget) { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget); + if (hideEvent.defaultPrevented) { + return; + } + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.off(element, 'mouseover', noop); + } + } + if (this._popper) { + this._popper.destroy(); + } + this._menu.classList.remove(CLASS_NAME_SHOW$6); + this._element.classList.remove(CLASS_NAME_SHOW$6); + this._element.setAttribute('aria-expanded', 'false'); + Manipulator.removeDataAttribute(this._menu, 'popper'); + EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget); + } + _getConfig(config) { + config = super._getConfig(config); + if (typeof config.reference === 'object' && !isElement$1(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') { + // Popper virtual elements require a getBoundingClientRect method + throw new TypeError(`${NAME$a.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`); + } + return config; + } + _createPopper() { + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)'); + } + let referenceElement = this._element; + if (this._config.reference === 'parent') { + referenceElement = this._parent; + } else if (isElement$1(this._config.reference)) { + referenceElement = getElement(this._config.reference); + } else if (typeof this._config.reference === 'object') { + referenceElement = this._config.reference; + } + const popperConfig = this._getPopperConfig(); + this._popper = createPopper(referenceElement, this._menu, popperConfig); + } + _isShown() { + return this._menu.classList.contains(CLASS_NAME_SHOW$6); + } + _getPlacement() { + const parentDropdown = this._parent; + if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { + return PLACEMENT_RIGHT; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { + return PLACEMENT_LEFT; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) { + return PLACEMENT_TOPCENTER; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) { + return PLACEMENT_BOTTOMCENTER; + } + + // We need to trim the value because custom properties can also include spaces + const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'; + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { + return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP; + } + return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM; + } + _detectNavbar() { + return this._element.closest(SELECTOR_NAVBAR) !== null; + } + _getOffset() { + const { + offset + } = this._config; + if (typeof offset === 'string') { + return offset.split(',').map(value => Number.parseInt(value, 10)); + } + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + return offset; + } + _getPopperConfig() { + const defaultBsPopperConfig = { + placement: this._getPlacement(), + modifiers: [{ + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }] + }; + + // Disable Popper if we have a static display or Dropdown is in Navbar + if (this._inNavbar || this._config.display === 'static') { + Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove + defaultBsPopperConfig.modifiers = [{ + name: 'applyStyles', + enabled: false + }]; + } + return { + ...defaultBsPopperConfig, + ...execute(this._config.popperConfig, [defaultBsPopperConfig]) + }; + } + _selectMenuItem({ + key, + target + }) { + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element)); + if (!items.length) { + return; + } + + // if target isn't included in items (e.g. when expanding the dropdown) + // allow cycling to get the last item in case key equals ARROW_UP_KEY + getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus(); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Dropdown.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + static clearMenus(event) { + if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) { + return; + } + const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN); + for (const toggle of openToggles) { + const context = Dropdown.getInstance(toggle); + if (!context || context._config.autoClose === false) { + continue; + } + const composedPath = event.composedPath(); + const isMenuTarget = composedPath.includes(context._menu); + if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) { + continue; + } + + // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu + if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) { + continue; + } + const relatedTarget = { + relatedTarget: context._element + }; + if (event.type === 'click') { + relatedTarget.clickEvent = event; + } + context._completeHide(relatedTarget); + } + } + static dataApiKeydownHandler(event) { + // If not an UP | DOWN | ESCAPE key => not a dropdown command + // If input/textarea && if key is other than ESCAPE => not a dropdown command + + const isInput = /input|textarea/i.test(event.target.tagName); + const isEscapeEvent = event.key === ESCAPE_KEY$2; + const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key); + if (!isUpOrDownEvent && !isEscapeEvent) { + return; + } + if (isInput && !isEscapeEvent) { + return; + } + event.preventDefault(); + + // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/ + const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode); + const instance = Dropdown.getOrCreateInstance(getToggleButton); + if (isUpOrDownEvent) { + event.stopPropagation(); + instance.show(); + instance._selectMenuItem(event); + return; + } + if (instance._isShown()) { + // else is escape and we check if it is shown + event.stopPropagation(); + instance.hide(); + getToggleButton.focus(); + } + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus); + EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) { + event.preventDefault(); + Dropdown.getOrCreateInstance(this).toggle(); + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Dropdown); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/backdrop.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$9 = 'backdrop'; + const CLASS_NAME_FADE$4 = 'fade'; + const CLASS_NAME_SHOW$5 = 'show'; + const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`; + const Default$8 = { + className: 'modal-backdrop', + clickCallback: null, + isAnimated: false, + isVisible: true, + // if false, we use the backdrop helper without adding any element to the dom + rootElement: 'body' // give the choice to place backdrop under different elements + }; + const DefaultType$8 = { + className: 'string', + clickCallback: '(function|null)', + isAnimated: 'boolean', + isVisible: 'boolean', + rootElement: '(element|string)' + }; + + /** + * Class definition + */ + + class Backdrop extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + this._isAppended = false; + this._element = null; + } + + // Getters + static get Default() { + return Default$8; + } + static get DefaultType() { + return DefaultType$8; + } + static get NAME() { + return NAME$9; + } + + // Public + show(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + this._append(); + const element = this._getElement(); + if (this._config.isAnimated) { + reflow(element); + } + element.classList.add(CLASS_NAME_SHOW$5); + this._emulateAnimation(() => { + execute(callback); + }); + } + hide(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + this._getElement().classList.remove(CLASS_NAME_SHOW$5); + this._emulateAnimation(() => { + this.dispose(); + execute(callback); + }); + } + dispose() { + if (!this._isAppended) { + return; + } + EventHandler.off(this._element, EVENT_MOUSEDOWN); + this._element.remove(); + this._isAppended = false; + } + + // Private + _getElement() { + if (!this._element) { + const backdrop = document.createElement('div'); + backdrop.className = this._config.className; + if (this._config.isAnimated) { + backdrop.classList.add(CLASS_NAME_FADE$4); + } + this._element = backdrop; + } + return this._element; + } + _configAfterMerge(config) { + // use getElement() with the default "body" to get a fresh Element on each instantiation + config.rootElement = getElement(config.rootElement); + return config; + } + _append() { + if (this._isAppended) { + return; + } + const element = this._getElement(); + this._config.rootElement.append(element); + EventHandler.on(element, EVENT_MOUSEDOWN, () => { + execute(this._config.clickCallback); + }); + this._isAppended = true; + } + _emulateAnimation(callback) { + executeAfterTransition(callback, this._getElement(), this._config.isAnimated); + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/focustrap.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$8 = 'focustrap'; + const DATA_KEY$5 = 'bs.focustrap'; + const EVENT_KEY$5 = `.${DATA_KEY$5}`; + const EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`; + const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`; + const TAB_KEY = 'Tab'; + const TAB_NAV_FORWARD = 'forward'; + const TAB_NAV_BACKWARD = 'backward'; + const Default$7 = { + autofocus: true, + trapElement: null // The element to trap focus inside of + }; + const DefaultType$7 = { + autofocus: 'boolean', + trapElement: 'element' + }; + + /** + * Class definition + */ + + class FocusTrap extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + this._isActive = false; + this._lastTabNavDirection = null; + } + + // Getters + static get Default() { + return Default$7; + } + static get DefaultType() { + return DefaultType$7; + } + static get NAME() { + return NAME$8; + } + + // Public + activate() { + if (this._isActive) { + return; + } + if (this._config.autofocus) { + this._config.trapElement.focus(); + } + EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop + EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event)); + EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event)); + this._isActive = true; + } + deactivate() { + if (!this._isActive) { + return; + } + this._isActive = false; + EventHandler.off(document, EVENT_KEY$5); + } + + // Private + _handleFocusin(event) { + const { + trapElement + } = this._config; + if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) { + return; + } + const elements = SelectorEngine.focusableChildren(trapElement); + if (elements.length === 0) { + trapElement.focus(); + } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) { + elements[elements.length - 1].focus(); + } else { + elements[0].focus(); + } + } + _handleKeydown(event) { + if (event.key !== TAB_KEY) { + return; + } + this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/scrollBar.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'; + const SELECTOR_STICKY_CONTENT = '.sticky-top'; + const PROPERTY_PADDING = 'padding-right'; + const PROPERTY_MARGIN = 'margin-right'; + + /** + * Class definition + */ + + class ScrollBarHelper { + constructor() { + this._element = document.body; + } + + // Public + getWidth() { + // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes + const documentWidth = document.documentElement.clientWidth; + return Math.abs(window.innerWidth - documentWidth); + } + hide() { + const width = this.getWidth(); + this._disableOverFlow(); + // give padding to element to balance the hidden scrollbar width + this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width); + // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth + this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width); + this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width); + } + reset() { + this._resetElementAttributes(this._element, 'overflow'); + this._resetElementAttributes(this._element, PROPERTY_PADDING); + this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING); + this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN); + } + isOverflowing() { + return this.getWidth() > 0; + } + + // Private + _disableOverFlow() { + this._saveInitialAttribute(this._element, 'overflow'); + this._element.style.overflow = 'hidden'; + } + _setElementAttributes(selector, styleProperty, callback) { + const scrollbarWidth = this.getWidth(); + const manipulationCallBack = element => { + if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { + return; + } + this._saveInitialAttribute(element, styleProperty); + const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty); + element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`); + }; + this._applyManipulationCallback(selector, manipulationCallBack); + } + _saveInitialAttribute(element, styleProperty) { + const actualValue = element.style.getPropertyValue(styleProperty); + if (actualValue) { + Manipulator.setDataAttribute(element, styleProperty, actualValue); + } + } + _resetElementAttributes(selector, styleProperty) { + const manipulationCallBack = element => { + const value = Manipulator.getDataAttribute(element, styleProperty); + // We only want to remove the property if the value is `null`; the value can also be zero + if (value === null) { + element.style.removeProperty(styleProperty); + return; + } + Manipulator.removeDataAttribute(element, styleProperty); + element.style.setProperty(styleProperty, value); + }; + this._applyManipulationCallback(selector, manipulationCallBack); + } + _applyManipulationCallback(selector, callBack) { + if (isElement$1(selector)) { + callBack(selector); + return; + } + for (const sel of SelectorEngine.find(selector, this._element)) { + callBack(sel); + } + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap modal.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$7 = 'modal'; + const DATA_KEY$4 = 'bs.modal'; + const EVENT_KEY$4 = `.${DATA_KEY$4}`; + const DATA_API_KEY$2 = '.data-api'; + const ESCAPE_KEY$1 = 'Escape'; + const EVENT_HIDE$4 = `hide${EVENT_KEY$4}`; + const EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`; + const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`; + const EVENT_SHOW$4 = `show${EVENT_KEY$4}`; + const EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`; + const EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`; + const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`; + const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`; + const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`; + const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`; + const CLASS_NAME_OPEN = 'modal-open'; + const CLASS_NAME_FADE$3 = 'fade'; + const CLASS_NAME_SHOW$4 = 'show'; + const CLASS_NAME_STATIC = 'modal-static'; + const OPEN_SELECTOR$1 = '.modal.show'; + const SELECTOR_DIALOG = '.modal-dialog'; + const SELECTOR_MODAL_BODY = '.modal-body'; + const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]'; + const Default$6 = { + backdrop: true, + focus: true, + keyboard: true + }; + const DefaultType$6 = { + backdrop: '(boolean|string)', + focus: 'boolean', + keyboard: 'boolean' + }; + + /** + * Class definition + */ + + class Modal extends BaseComponent { + constructor(element, config) { + super(element, config); + this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element); + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._isShown = false; + this._isTransitioning = false; + this._scrollBar = new ScrollBarHelper(); + this._addEventListeners(); + } + + // Getters + static get Default() { + return Default$6; + } + static get DefaultType() { + return DefaultType$6; + } + static get NAME() { + return NAME$7; + } + + // Public + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + show(relatedTarget) { + if (this._isShown || this._isTransitioning) { + return; + } + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, { + relatedTarget + }); + if (showEvent.defaultPrevented) { + return; + } + this._isShown = true; + this._isTransitioning = true; + this._scrollBar.hide(); + document.body.classList.add(CLASS_NAME_OPEN); + this._adjustDialog(); + this._backdrop.show(() => this._showElement(relatedTarget)); + } + hide() { + if (!this._isShown || this._isTransitioning) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4); + if (hideEvent.defaultPrevented) { + return; + } + this._isShown = false; + this._isTransitioning = true; + this._focustrap.deactivate(); + this._element.classList.remove(CLASS_NAME_SHOW$4); + this._queueCallback(() => this._hideModal(), this._element, this._isAnimated()); + } + dispose() { + EventHandler.off(window, EVENT_KEY$4); + EventHandler.off(this._dialog, EVENT_KEY$4); + this._backdrop.dispose(); + this._focustrap.deactivate(); + super.dispose(); + } + handleUpdate() { + this._adjustDialog(); + } + + // Private + _initializeBackDrop() { + return new Backdrop({ + isVisible: Boolean(this._config.backdrop), + // 'static' option will be translated to true, and booleans will keep their value, + isAnimated: this._isAnimated() + }); + } + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + _showElement(relatedTarget) { + // try to append dynamic modal + if (!document.body.contains(this._element)) { + document.body.append(this._element); + } + this._element.style.display = 'block'; + this._element.removeAttribute('aria-hidden'); + this._element.setAttribute('aria-modal', true); + this._element.setAttribute('role', 'dialog'); + this._element.scrollTop = 0; + const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog); + if (modalBody) { + modalBody.scrollTop = 0; + } + reflow(this._element); + this._element.classList.add(CLASS_NAME_SHOW$4); + const transitionComplete = () => { + if (this._config.focus) { + this._focustrap.activate(); + } + this._isTransitioning = false; + EventHandler.trigger(this._element, EVENT_SHOWN$4, { + relatedTarget + }); + }; + this._queueCallback(transitionComplete, this._dialog, this._isAnimated()); + } + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => { + if (event.key !== ESCAPE_KEY$1) { + return; + } + if (this._config.keyboard) { + this.hide(); + return; + } + this._triggerBackdropTransition(); + }); + EventHandler.on(window, EVENT_RESIZE$1, () => { + if (this._isShown && !this._isTransitioning) { + this._adjustDialog(); + } + }); + EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => { + // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks + EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => { + if (this._element !== event.target || this._element !== event2.target) { + return; + } + if (this._config.backdrop === 'static') { + this._triggerBackdropTransition(); + return; + } + if (this._config.backdrop) { + this.hide(); + } + }); + }); + } + _hideModal() { + this._element.style.display = 'none'; + this._element.setAttribute('aria-hidden', true); + this._element.removeAttribute('aria-modal'); + this._element.removeAttribute('role'); + this._isTransitioning = false; + this._backdrop.hide(() => { + document.body.classList.remove(CLASS_NAME_OPEN); + this._resetAdjustments(); + this._scrollBar.reset(); + EventHandler.trigger(this._element, EVENT_HIDDEN$4); + }); + } + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_FADE$3); + } + _triggerBackdropTransition() { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1); + if (hideEvent.defaultPrevented) { + return; + } + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + const initialOverflowY = this._element.style.overflowY; + // return if the following background transition hasn't yet completed + if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) { + return; + } + if (!isModalOverflowing) { + this._element.style.overflowY = 'hidden'; + } + this._element.classList.add(CLASS_NAME_STATIC); + this._queueCallback(() => { + this._element.classList.remove(CLASS_NAME_STATIC); + this._queueCallback(() => { + this._element.style.overflowY = initialOverflowY; + }, this._dialog); + }, this._dialog); + this._element.focus(); + } + + /** + * The following methods are used to handle overflowing modals + */ + + _adjustDialog() { + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + const scrollbarWidth = this._scrollBar.getWidth(); + const isBodyOverflowing = scrollbarWidth > 0; + if (isBodyOverflowing && !isModalOverflowing) { + const property = isRTL() ? 'paddingLeft' : 'paddingRight'; + this._element.style[property] = `${scrollbarWidth}px`; + } + if (!isBodyOverflowing && isModalOverflowing) { + const property = isRTL() ? 'paddingRight' : 'paddingLeft'; + this._element.style[property] = `${scrollbarWidth}px`; + } + } + _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + } + + // Static + static jQueryInterface(config, relatedTarget) { + return this.each(function () { + const data = Modal.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](relatedTarget); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + EventHandler.one(target, EVENT_SHOW$4, showEvent => { + if (showEvent.defaultPrevented) { + // only register focus restorer if modal will actually get shown + return; + } + EventHandler.one(target, EVENT_HIDDEN$4, () => { + if (isVisible(this)) { + this.focus(); + } + }); + }); + + // avoid conflict when clicking modal toggler while another one is open + const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1); + if (alreadyOpen) { + Modal.getInstance(alreadyOpen).hide(); + } + const data = Modal.getOrCreateInstance(target); + data.toggle(this); + }); + enableDismissTrigger(Modal); + + /** + * jQuery + */ + + defineJQueryPlugin(Modal); + + /** + * -------------------------------------------------------------------------- + * Bootstrap offcanvas.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$6 = 'offcanvas'; + const DATA_KEY$3 = 'bs.offcanvas'; + const EVENT_KEY$3 = `.${DATA_KEY$3}`; + const DATA_API_KEY$1 = '.data-api'; + const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`; + const ESCAPE_KEY = 'Escape'; + const CLASS_NAME_SHOW$3 = 'show'; + const CLASS_NAME_SHOWING$1 = 'showing'; + const CLASS_NAME_HIDING = 'hiding'; + const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'; + const OPEN_SELECTOR = '.offcanvas.show'; + const EVENT_SHOW$3 = `show${EVENT_KEY$3}`; + const EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`; + const EVENT_HIDE$3 = `hide${EVENT_KEY$3}`; + const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`; + const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`; + const EVENT_RESIZE = `resize${EVENT_KEY$3}`; + const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`; + const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`; + const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]'; + const Default$5 = { + backdrop: true, + keyboard: true, + scroll: false + }; + const DefaultType$5 = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + scroll: 'boolean' + }; + + /** + * Class definition + */ + + class Offcanvas extends BaseComponent { + constructor(element, config) { + super(element, config); + this._isShown = false; + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._addEventListeners(); + } + + // Getters + static get Default() { + return Default$5; + } + static get DefaultType() { + return DefaultType$5; + } + static get NAME() { + return NAME$6; + } + + // Public + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + show(relatedTarget) { + if (this._isShown) { + return; + } + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, { + relatedTarget + }); + if (showEvent.defaultPrevented) { + return; + } + this._isShown = true; + this._backdrop.show(); + if (!this._config.scroll) { + new ScrollBarHelper().hide(); + } + this._element.setAttribute('aria-modal', true); + this._element.setAttribute('role', 'dialog'); + this._element.classList.add(CLASS_NAME_SHOWING$1); + const completeCallBack = () => { + if (!this._config.scroll || this._config.backdrop) { + this._focustrap.activate(); + } + this._element.classList.add(CLASS_NAME_SHOW$3); + this._element.classList.remove(CLASS_NAME_SHOWING$1); + EventHandler.trigger(this._element, EVENT_SHOWN$3, { + relatedTarget + }); + }; + this._queueCallback(completeCallBack, this._element, true); + } + hide() { + if (!this._isShown) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3); + if (hideEvent.defaultPrevented) { + return; + } + this._focustrap.deactivate(); + this._element.blur(); + this._isShown = false; + this._element.classList.add(CLASS_NAME_HIDING); + this._backdrop.hide(); + const completeCallback = () => { + this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING); + this._element.removeAttribute('aria-modal'); + this._element.removeAttribute('role'); + if (!this._config.scroll) { + new ScrollBarHelper().reset(); + } + EventHandler.trigger(this._element, EVENT_HIDDEN$3); + }; + this._queueCallback(completeCallback, this._element, true); + } + dispose() { + this._backdrop.dispose(); + this._focustrap.deactivate(); + super.dispose(); + } + + // Private + _initializeBackDrop() { + const clickCallback = () => { + if (this._config.backdrop === 'static') { + EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + return; + } + this.hide(); + }; + + // 'static' option will be translated to true, and booleans will keep their value + const isVisible = Boolean(this._config.backdrop); + return new Backdrop({ + className: CLASS_NAME_BACKDROP, + isVisible, + isAnimated: true, + rootElement: this._element.parentNode, + clickCallback: isVisible ? clickCallback : null + }); + } + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => { + if (event.key !== ESCAPE_KEY) { + return; + } + if (this._config.keyboard) { + this.hide(); + return; + } + EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + }); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Offcanvas.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + EventHandler.one(target, EVENT_HIDDEN$3, () => { + // focus on trigger when it is closed + if (isVisible(this)) { + this.focus(); + } + }); + + // avoid conflict when clicking a toggler of an offcanvas, while another is open + const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR); + if (alreadyOpen && alreadyOpen !== target) { + Offcanvas.getInstance(alreadyOpen).hide(); + } + const data = Offcanvas.getOrCreateInstance(target); + data.toggle(this); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => { + for (const selector of SelectorEngine.find(OPEN_SELECTOR)) { + Offcanvas.getOrCreateInstance(selector).show(); + } + }); + EventHandler.on(window, EVENT_RESIZE, () => { + for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) { + if (getComputedStyle(element).position !== 'fixed') { + Offcanvas.getOrCreateInstance(element).hide(); + } + } + }); + enableDismissTrigger(Offcanvas); + + /** + * jQuery + */ + + defineJQueryPlugin(Offcanvas); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/sanitizer.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + // js-docs-start allow-list + const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; + const DefaultAllowlist = { + // Global attributes allowed on any supplied element below. + '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], + a: ['target', 'href', 'title', 'rel'], + area: [], + b: [], + br: [], + col: [], + code: [], + dd: [], + div: [], + dl: [], + dt: [], + em: [], + hr: [], + h1: [], + h2: [], + h3: [], + h4: [], + h5: [], + h6: [], + i: [], + img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], + li: [], + ol: [], + p: [], + pre: [], + s: [], + small: [], + span: [], + sub: [], + sup: [], + strong: [], + u: [], + ul: [] + }; + // js-docs-end allow-list + + const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']); + + /** + * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation + * contexts. + * + * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38 + */ + // eslint-disable-next-line unicorn/better-regex + const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i; + const allowedAttribute = (attribute, allowedAttributeList) => { + const attributeName = attribute.nodeName.toLowerCase(); + if (allowedAttributeList.includes(attributeName)) { + if (uriAttributes.has(attributeName)) { + return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue)); + } + return true; + } + + // Check if a regular expression validates the attribute. + return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName)); + }; + function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) { + if (!unsafeHtml.length) { + return unsafeHtml; + } + if (sanitizeFunction && typeof sanitizeFunction === 'function') { + return sanitizeFunction(unsafeHtml); + } + const domParser = new window.DOMParser(); + const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); + const elements = [].concat(...createdDocument.body.querySelectorAll('*')); + for (const element of elements) { + const elementName = element.nodeName.toLowerCase(); + if (!Object.keys(allowList).includes(elementName)) { + element.remove(); + continue; + } + const attributeList = [].concat(...element.attributes); + const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []); + for (const attribute of attributeList) { + if (!allowedAttribute(attribute, allowedAttributes)) { + element.removeAttribute(attribute.nodeName); + } + } + } + return createdDocument.body.innerHTML; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/template-factory.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$5 = 'TemplateFactory'; + const Default$4 = { + allowList: DefaultAllowlist, + content: {}, + // { selector : text , selector2 : text2 , } + extraClass: '', + html: false, + sanitize: true, + sanitizeFn: null, + template: '
' + }; + const DefaultType$4 = { + allowList: 'object', + content: 'object', + extraClass: '(string|function)', + html: 'boolean', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + template: 'string' + }; + const DefaultContentType = { + entry: '(string|element|function|null)', + selector: '(string|element)' + }; + + /** + * Class definition + */ + + class TemplateFactory extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + } + + // Getters + static get Default() { + return Default$4; + } + static get DefaultType() { + return DefaultType$4; + } + static get NAME() { + return NAME$5; + } + + // Public + getContent() { + return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean); + } + hasContent() { + return this.getContent().length > 0; + } + changeContent(content) { + this._checkContent(content); + this._config.content = { + ...this._config.content, + ...content + }; + return this; + } + toHtml() { + const templateWrapper = document.createElement('div'); + templateWrapper.innerHTML = this._maybeSanitize(this._config.template); + for (const [selector, text] of Object.entries(this._config.content)) { + this._setContent(templateWrapper, text, selector); + } + const template = templateWrapper.children[0]; + const extraClass = this._resolvePossibleFunction(this._config.extraClass); + if (extraClass) { + template.classList.add(...extraClass.split(' ')); + } + return template; + } + + // Private + _typeCheckConfig(config) { + super._typeCheckConfig(config); + this._checkContent(config.content); + } + _checkContent(arg) { + for (const [selector, content] of Object.entries(arg)) { + super._typeCheckConfig({ + selector, + entry: content + }, DefaultContentType); + } + } + _setContent(template, content, selector) { + const templateElement = SelectorEngine.findOne(selector, template); + if (!templateElement) { + return; + } + content = this._resolvePossibleFunction(content); + if (!content) { + templateElement.remove(); + return; + } + if (isElement$1(content)) { + this._putElementInTemplate(getElement(content), templateElement); + return; + } + if (this._config.html) { + templateElement.innerHTML = this._maybeSanitize(content); + return; + } + templateElement.textContent = content; + } + _maybeSanitize(arg) { + return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg; + } + _resolvePossibleFunction(arg) { + return execute(arg, [this]); + } + _putElementInTemplate(element, templateElement) { + if (this._config.html) { + templateElement.innerHTML = ''; + templateElement.append(element); + return; + } + templateElement.textContent = element.textContent; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap tooltip.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$4 = 'tooltip'; + const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); + const CLASS_NAME_FADE$2 = 'fade'; + const CLASS_NAME_MODAL = 'modal'; + const CLASS_NAME_SHOW$2 = 'show'; + const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'; + const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; + const EVENT_MODAL_HIDE = 'hide.bs.modal'; + const TRIGGER_HOVER = 'hover'; + const TRIGGER_FOCUS = 'focus'; + const TRIGGER_CLICK = 'click'; + const TRIGGER_MANUAL = 'manual'; + const EVENT_HIDE$2 = 'hide'; + const EVENT_HIDDEN$2 = 'hidden'; + const EVENT_SHOW$2 = 'show'; + const EVENT_SHOWN$2 = 'shown'; + const EVENT_INSERTED = 'inserted'; + const EVENT_CLICK$1 = 'click'; + const EVENT_FOCUSIN$1 = 'focusin'; + const EVENT_FOCUSOUT$1 = 'focusout'; + const EVENT_MOUSEENTER = 'mouseenter'; + const EVENT_MOUSELEAVE = 'mouseleave'; + const AttachmentMap = { + AUTO: 'auto', + TOP: 'top', + RIGHT: isRTL() ? 'left' : 'right', + BOTTOM: 'bottom', + LEFT: isRTL() ? 'right' : 'left' + }; + const Default$3 = { + allowList: DefaultAllowlist, + animation: true, + boundary: 'clippingParents', + container: false, + customClass: '', + delay: 0, + fallbackPlacements: ['top', 'right', 'bottom', 'left'], + html: false, + offset: [0, 6], + placement: 'top', + popperConfig: null, + sanitize: true, + sanitizeFn: null, + selector: false, + template: '', + title: '', + trigger: 'hover focus' + }; + const DefaultType$3 = { + allowList: 'object', + animation: 'boolean', + boundary: '(string|element)', + container: '(string|element|boolean)', + customClass: '(string|function)', + delay: '(number|object)', + fallbackPlacements: 'array', + html: 'boolean', + offset: '(array|string|function)', + placement: '(string|function)', + popperConfig: '(null|object|function)', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + selector: '(string|boolean)', + template: 'string', + title: '(string|element|function)', + trigger: 'string' + }; + + /** + * Class definition + */ + + class Tooltip extends BaseComponent { + constructor(element, config) { + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)'); + } + super(element, config); + + // Private + this._isEnabled = true; + this._timeout = 0; + this._isHovered = null; + this._activeTrigger = {}; + this._popper = null; + this._templateFactory = null; + this._newContent = null; + + // Protected + this.tip = null; + this._setListeners(); + if (!this._config.selector) { + this._fixTitle(); + } + } + + // Getters + static get Default() { + return Default$3; + } + static get DefaultType() { + return DefaultType$3; + } + static get NAME() { + return NAME$4; + } + + // Public + enable() { + this._isEnabled = true; + } + disable() { + this._isEnabled = false; + } + toggleEnabled() { + this._isEnabled = !this._isEnabled; + } + toggle() { + if (!this._isEnabled) { + return; + } + this._activeTrigger.click = !this._activeTrigger.click; + if (this._isShown()) { + this._leave(); + return; + } + this._enter(); + } + dispose() { + clearTimeout(this._timeout); + EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + if (this._element.getAttribute('data-bs-original-title')) { + this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title')); + } + this._disposePopper(); + super.dispose(); + } + show() { + if (this._element.style.display === 'none') { + throw new Error('Please use show on visible elements'); + } + if (!(this._isWithContent() && this._isEnabled)) { + return; + } + const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2)); + const shadowRoot = findShadowRoot(this._element); + const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element); + if (showEvent.defaultPrevented || !isInTheDom) { + return; + } + + // TODO: v6 remove this or make it optional + this._disposePopper(); + const tip = this._getTipElement(); + this._element.setAttribute('aria-describedby', tip.getAttribute('id')); + const { + container + } = this._config; + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { + container.append(tip); + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)); + } + this._popper = this._createPopper(tip); + tip.classList.add(CLASS_NAME_SHOW$2); + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.on(element, 'mouseover', noop); + } + } + const complete = () => { + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2)); + if (this._isHovered === false) { + this._leave(); + } + this._isHovered = false; + }; + this._queueCallback(complete, this.tip, this._isAnimated()); + } + hide() { + if (!this._isShown()) { + return; + } + const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2)); + if (hideEvent.defaultPrevented) { + return; + } + const tip = this._getTipElement(); + tip.classList.remove(CLASS_NAME_SHOW$2); + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.off(element, 'mouseover', noop); + } + } + this._activeTrigger[TRIGGER_CLICK] = false; + this._activeTrigger[TRIGGER_FOCUS] = false; + this._activeTrigger[TRIGGER_HOVER] = false; + this._isHovered = null; // it is a trick to support manual triggering + + const complete = () => { + if (this._isWithActiveTrigger()) { + return; + } + if (!this._isHovered) { + this._disposePopper(); + } + this._element.removeAttribute('aria-describedby'); + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2)); + }; + this._queueCallback(complete, this.tip, this._isAnimated()); + } + update() { + if (this._popper) { + this._popper.update(); + } + } + + // Protected + _isWithContent() { + return Boolean(this._getTitle()); + } + _getTipElement() { + if (!this.tip) { + this.tip = this._createTipElement(this._newContent || this._getContentForTemplate()); + } + return this.tip; + } + _createTipElement(content) { + const tip = this._getTemplateFactory(content).toHtml(); + + // TODO: remove this check in v6 + if (!tip) { + return null; + } + tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2); + // TODO: v6 the following can be achieved with CSS only + tip.classList.add(`bs-${this.constructor.NAME}-auto`); + const tipId = getUID(this.constructor.NAME).toString(); + tip.setAttribute('id', tipId); + if (this._isAnimated()) { + tip.classList.add(CLASS_NAME_FADE$2); + } + return tip; + } + setContent(content) { + this._newContent = content; + if (this._isShown()) { + this._disposePopper(); + this.show(); + } + } + _getTemplateFactory(content) { + if (this._templateFactory) { + this._templateFactory.changeContent(content); + } else { + this._templateFactory = new TemplateFactory({ + ...this._config, + // the `content` var has to be after `this._config` + // to override config.content in case of popover + content, + extraClass: this._resolvePossibleFunction(this._config.customClass) + }); + } + return this._templateFactory; + } + _getContentForTemplate() { + return { + [SELECTOR_TOOLTIP_INNER]: this._getTitle() + }; + } + _getTitle() { + return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title'); + } + + // Private + _initializeOnDelegatedTarget(event) { + return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); + } + _isAnimated() { + return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2); + } + _isShown() { + return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2); + } + _createPopper(tip) { + const placement = execute(this._config.placement, [this, tip, this._element]); + const attachment = AttachmentMap[placement.toUpperCase()]; + return createPopper(this._element, tip, this._getPopperConfig(attachment)); + } + _getOffset() { + const { + offset + } = this._config; + if (typeof offset === 'string') { + return offset.split(',').map(value => Number.parseInt(value, 10)); + } + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + return offset; + } + _resolvePossibleFunction(arg) { + return execute(arg, [this._element]); + } + _getPopperConfig(attachment) { + const defaultBsPopperConfig = { + placement: attachment, + modifiers: [{ + name: 'flip', + options: { + fallbackPlacements: this._config.fallbackPlacements + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }, { + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'arrow', + options: { + element: `.${this.constructor.NAME}-arrow` + } + }, { + name: 'preSetPlacement', + enabled: true, + phase: 'beforeMain', + fn: data => { + // Pre-set Popper's placement attribute in order to read the arrow sizes properly. + // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement + this._getTipElement().setAttribute('data-popper-placement', data.state.placement); + } + }] + }; + return { + ...defaultBsPopperConfig, + ...execute(this._config.popperConfig, [defaultBsPopperConfig]) + }; + } + _setListeners() { + const triggers = this._config.trigger.split(' '); + for (const trigger of triggers) { + if (trigger === 'click') { + EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context.toggle(); + }); + } else if (trigger !== TRIGGER_MANUAL) { + const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1); + const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1); + EventHandler.on(this._element, eventIn, this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; + context._enter(); + }); + EventHandler.on(this._element, eventOut, this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget); + context._leave(); + }); + } + } + this._hideModalHandler = () => { + if (this._element) { + this.hide(); + } + }; + EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + } + _fixTitle() { + const title = this._element.getAttribute('title'); + if (!title) { + return; + } + if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) { + this._element.setAttribute('aria-label', title); + } + this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility + this._element.removeAttribute('title'); + } + _enter() { + if (this._isShown() || this._isHovered) { + this._isHovered = true; + return; + } + this._isHovered = true; + this._setTimeout(() => { + if (this._isHovered) { + this.show(); + } + }, this._config.delay.show); + } + _leave() { + if (this._isWithActiveTrigger()) { + return; + } + this._isHovered = false; + this._setTimeout(() => { + if (!this._isHovered) { + this.hide(); + } + }, this._config.delay.hide); + } + _setTimeout(handler, timeout) { + clearTimeout(this._timeout); + this._timeout = setTimeout(handler, timeout); + } + _isWithActiveTrigger() { + return Object.values(this._activeTrigger).includes(true); + } + _getConfig(config) { + const dataAttributes = Manipulator.getDataAttributes(this._element); + for (const dataAttribute of Object.keys(dataAttributes)) { + if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) { + delete dataAttributes[dataAttribute]; + } + } + config = { + ...dataAttributes, + ...(typeof config === 'object' && config ? config : {}) + }; + config = this._mergeConfigObj(config); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + _configAfterMerge(config) { + config.container = config.container === false ? document.body : getElement(config.container); + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + return config; + } + _getDelegateConfig() { + const config = {}; + for (const [key, value] of Object.entries(this._config)) { + if (this.constructor.Default[key] !== value) { + config[key] = value; + } + } + config.selector = false; + config.trigger = 'manual'; + + // In the future can be replaced with: + // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]]) + // `Object.fromEntries(keysWithDifferentValues)` + return config; + } + _disposePopper() { + if (this._popper) { + this._popper.destroy(); + this._popper = null; + } + if (this.tip) { + this.tip.remove(); + this.tip = null; + } + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Tooltip.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * jQuery + */ + + defineJQueryPlugin(Tooltip); + + /** + * -------------------------------------------------------------------------- + * Bootstrap popover.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$3 = 'popover'; + const SELECTOR_TITLE = '.popover-header'; + const SELECTOR_CONTENT = '.popover-body'; + const Default$2 = { + ...Tooltip.Default, + content: '', + offset: [0, 8], + placement: 'right', + template: '', + trigger: 'click' + }; + const DefaultType$2 = { + ...Tooltip.DefaultType, + content: '(null|string|element|function)' + }; + + /** + * Class definition + */ + + class Popover extends Tooltip { + // Getters + static get Default() { + return Default$2; + } + static get DefaultType() { + return DefaultType$2; + } + static get NAME() { + return NAME$3; + } + + // Overrides + _isWithContent() { + return this._getTitle() || this._getContent(); + } + + // Private + _getContentForTemplate() { + return { + [SELECTOR_TITLE]: this._getTitle(), + [SELECTOR_CONTENT]: this._getContent() + }; + } + _getContent() { + return this._resolvePossibleFunction(this._config.content); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Popover.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * jQuery + */ + + defineJQueryPlugin(Popover); + + /** + * -------------------------------------------------------------------------- + * Bootstrap scrollspy.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$2 = 'scrollspy'; + const DATA_KEY$2 = 'bs.scrollspy'; + const EVENT_KEY$2 = `.${DATA_KEY$2}`; + const DATA_API_KEY = '.data-api'; + const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`; + const EVENT_CLICK = `click${EVENT_KEY$2}`; + const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`; + const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'; + const CLASS_NAME_ACTIVE$1 = 'active'; + const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'; + const SELECTOR_TARGET_LINKS = '[href]'; + const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'; + const SELECTOR_NAV_LINKS = '.nav-link'; + const SELECTOR_NAV_ITEMS = '.nav-item'; + const SELECTOR_LIST_ITEMS = '.list-group-item'; + const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`; + const SELECTOR_DROPDOWN = '.dropdown'; + const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle'; + const Default$1 = { + offset: null, + // TODO: v6 @deprecated, keep it for backwards compatibility reasons + rootMargin: '0px 0px -25%', + smoothScroll: false, + target: null, + threshold: [0.1, 0.5, 1] + }; + const DefaultType$1 = { + offset: '(number|null)', + // TODO v6 @deprecated, keep it for backwards compatibility reasons + rootMargin: 'string', + smoothScroll: 'boolean', + target: 'element', + threshold: 'array' + }; + + /** + * Class definition + */ + + class ScrollSpy extends BaseComponent { + constructor(element, config) { + super(element, config); + + // this._element is the observablesContainer and config.target the menu links wrapper + this._targetLinks = new Map(); + this._observableSections = new Map(); + this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element; + this._activeTarget = null; + this._observer = null; + this._previousScrollData = { + visibleEntryTop: 0, + parentScrollTop: 0 + }; + this.refresh(); // initialize + } + + // Getters + static get Default() { + return Default$1; + } + static get DefaultType() { + return DefaultType$1; + } + static get NAME() { + return NAME$2; + } + + // Public + refresh() { + this._initializeTargetsAndObservables(); + this._maybeEnableSmoothScroll(); + if (this._observer) { + this._observer.disconnect(); + } else { + this._observer = this._getNewObserver(); + } + for (const section of this._observableSections.values()) { + this._observer.observe(section); + } + } + dispose() { + this._observer.disconnect(); + super.dispose(); + } + + // Private + _configAfterMerge(config) { + // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case + config.target = getElement(config.target) || document.body; + + // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only + config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin; + if (typeof config.threshold === 'string') { + config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value)); + } + return config; + } + _maybeEnableSmoothScroll() { + if (!this._config.smoothScroll) { + return; + } + + // unregister any previous listeners + EventHandler.off(this._config.target, EVENT_CLICK); + EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => { + const observableSection = this._observableSections.get(event.target.hash); + if (observableSection) { + event.preventDefault(); + const root = this._rootElement || window; + const height = observableSection.offsetTop - this._element.offsetTop; + if (root.scrollTo) { + root.scrollTo({ + top: height, + behavior: 'smooth' + }); + return; + } + + // Chrome 60 doesn't support `scrollTo` + root.scrollTop = height; + } + }); + } + _getNewObserver() { + const options = { + root: this._rootElement, + threshold: this._config.threshold, + rootMargin: this._config.rootMargin + }; + return new IntersectionObserver(entries => this._observerCallback(entries), options); + } + + // The logic of selection + _observerCallback(entries) { + const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`); + const activate = entry => { + this._previousScrollData.visibleEntryTop = entry.target.offsetTop; + this._process(targetElement(entry)); + }; + const parentScrollTop = (this._rootElement || document.documentElement).scrollTop; + const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop; + this._previousScrollData.parentScrollTop = parentScrollTop; + for (const entry of entries) { + if (!entry.isIntersecting) { + this._activeTarget = null; + this._clearActiveClass(targetElement(entry)); + continue; + } + const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop; + // if we are scrolling down, pick the bigger offsetTop + if (userScrollsDown && entryIsLowerThanPrevious) { + activate(entry); + // if parent isn't scrolled, let's keep the first visible item, breaking the iteration + if (!parentScrollTop) { + return; + } + continue; + } + + // if we are scrolling up, pick the smallest offsetTop + if (!userScrollsDown && !entryIsLowerThanPrevious) { + activate(entry); + } + } + } + _initializeTargetsAndObservables() { + this._targetLinks = new Map(); + this._observableSections = new Map(); + const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target); + for (const anchor of targetLinks) { + // ensure that the anchor has an id and is not disabled + if (!anchor.hash || isDisabled(anchor)) { + continue; + } + const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element); + + // ensure that the observableSection exists & is visible + if (isVisible(observableSection)) { + this._targetLinks.set(decodeURI(anchor.hash), anchor); + this._observableSections.set(anchor.hash, observableSection); + } + } + } + _process(target) { + if (this._activeTarget === target) { + return; + } + this._clearActiveClass(this._config.target); + this._activeTarget = target; + target.classList.add(CLASS_NAME_ACTIVE$1); + this._activateParents(target); + EventHandler.trigger(this._element, EVENT_ACTIVATE, { + relatedTarget: target + }); + } + _activateParents(target) { + // Activate dropdown parents + if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) { + SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1); + return; + } + for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) { + // Set triggered links parents as active + // With both
"),e.join("")}});var o=i.extend({initialize:function(t){P.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:t,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:t,beforeSetDimensions:t,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:t,beforeBuildLabels:t,buildLabels:function(){var e=this,n=e.options.labels||{},t=P.callback(n.generateLabels,[e.chart],e)||[];n.filter&&(t=t.filter(function(t){return n.filter(t,e.chart.data)})),e.options.reverse&&t.reverse(),e.legendItems=t},afterBuildLabels:t,beforeFit:t,fit:function(){var n,i,a,o,r,s,l,u=this,t=u.options,d=t.labels,t=t.display,h=u.ctx,e=C.global,c=P.valueOrDefault,f=c(d.fontSize,e.defaultFontSize),g=c(d.fontStyle,e.defaultFontStyle),c=c(d.fontFamily,e.defaultFontFamily),e=P.fontString(f,g,c),m=u.legendHitBoxes=[],p=u.minSize,g=u.isHorizontal();g?(p.width=u.maxWidth,p.height=t?10:0):(p.width=t?10:0,p.height=u.maxHeight),t&&(h.font=e,g?(n=u.lineWidths=[0],i=u.legendItems.length?f+d.padding:0,h.textAlign="left",h.textBaseline="top",P.each(u.legendItems,function(t,e){t=T(d,f)+f/2+h.measureText(t.text).width;n[n.length-1]+t+d.padding>=u.width&&(i+=f+d.padding,n[n.length]=u.left),m[e]={left:0,top:0,width:t,height:f},n[n.length-1]+=t+d.padding}),p.height+=i):(c=d.padding,a=u.columnWidths=[],o=d.padding,s=r=0,l=f+c,P.each(u.legendItems,function(t,e){t=T(d,f)+f/2+h.measureText(t.text).width;s+l>p.height&&(o+=r+d.padding,a.push(r),s=r=0),r=Math.max(r,t),s+=l,m[e]={left:0,top:0,width:t,height:f}}),o+=r,a.push(r),p.width+=o)),u.width=p.width,u.height=p.height},afterFit:t,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var c,f,t,g,e,n,m,p,v,y,b,x=this,_=x.options,k=_.labels,w=C.global,M=w.elements.line,S=x.width,D=x.lineWidths;_.display&&(c=x.ctx,t=(f=P.valueOrDefault)(k.fontColor,w.defaultFontColor),g=f(k.fontSize,w.defaultFontSize),n=f(k.fontStyle,w.defaultFontStyle),e=f(k.fontFamily,w.defaultFontFamily),n=P.fontString(g,n,e),c.textAlign="left",c.textBaseline="middle",c.lineWidth=.5,c.strokeStyle=t,c.fillStyle=t,c.font=n,m=T(k,g),p=x.legendHitBoxes,v=x.isHorizontal(),y=v?{x:x.left+(S-D[0])/2,y:x.top+k.padding,line:0}:{x:x.left+k.padding,y:x.top+k.padding,line:0},b=g+k.padding,P.each(x.legendItems,function(t,e){var n,i,a,o,r,s,l=c.measureText(t.text).width,u=m+g/2+l,d=y.x,h=y.y;v?S<=d+u&&(h=y.y+=b,y.line++,d=y.x=x.left+(S-D[y.line])/2):h+b>x.bottom&&(d=y.x=d+x.columnWidths[y.line]+k.padding,h=y.y=x.top+k.padding,y.line++),i=d,n=h,a=t,isNaN(m)||m<=0||(c.save(),c.fillStyle=f(a.fillStyle,w.defaultColor),c.lineCap=f(a.lineCap,M.borderCapStyle),c.lineDashOffset=f(a.lineDashOffset,M.borderDashOffset),c.lineJoin=f(a.lineJoin,M.borderJoinStyle),c.lineWidth=f(a.lineWidth,M.borderWidth),c.strokeStyle=f(a.strokeStyle,w.defaultColor),s=0===f(a.lineWidth,M.borderWidth),c.setLineDash&&c.setLineDash(f(a.lineDash,M.borderDash)),_.labels&&_.labels.usePointStyle?(r=(o=g*Math.SQRT2/2)/Math.SQRT2,P.canvas.drawPoint(c,a.pointStyle,o,i+r,n+r)):(s||c.strokeRect(i,n,m,g),c.fillRect(i,n,m,g)),c.restore()),p[e].left=d,p[e].top=h,a=h,o=t,r=l,i=m+(s=g/2)+(i=d),a+=s,c.fillText(o.text,i,a),o.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(i,a),c.lineTo(i+r,a),c.stroke()),v?y.x+=u+k.padding:y.y+=b}))},handleEvent:function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type,a=!1;if("mousemove"===i){if(!n.onHover)return}else{if("click"!==i)return;if(!n.onClick)return}var o=t.x,r=t.y;if(o>=e.left&&o<=e.right&&r>=e.top&&r<=e.bottom)for(var s=e.legendHitBoxes,l=0;l=u.left&&o<=u.left+u.width&&r>=u.top&&r<=u.top+u.height){if("click"===i){n.onClick.call(e,t.native,e.legendItems[l]),a=!0;break}if("mousemove"===i){n.onHover.call(e,t.native,e.legendItems[l]),a=!0;break}}}return a}});function r(t,e){var n=new o({ctx:t.ctx,options:e,chart:t});a.configure(t,n,e),a.addBox(t,n),t.legend=n}e.exports={id:"legend",_element:o,beforeInit:function(t){var e=t.options.legend;e&&r(t,e)},beforeUpdate:function(t){var e=t.options.legend,n=t.legend;e?(P.mergeIf(e,C.global.legend),n?(a.configure(t,n,e),n.options=e):r(t,e)):n&&(a.removeBox(t,n),delete t.legend)},afterEvent:function(t,e){t=t.legend;t&&t.handleEvent(e)}}},{25:25,26:26,30:30,45:45}],52:[function(t,e,n){"use strict";var y=t(25),i=t(26),b=t(45),a=t(30),t=b.noop,o=(y._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,lineHeight:1.2,padding:10,position:"top",text:"",weight:2e3}}),i.extend({initialize:function(t){b.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:t,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:t,beforeSetDimensions:t,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:t,beforeBuildLabels:t,buildLabels:t,afterBuildLabels:t,beforeFit:t,fit:function(){var t=b.valueOrDefault,e=this.options,n=e.display,t=t(e.fontSize,y.global.defaultFontSize),i=this.minSize,a=b.isArray(e.text)?e.text.length:1,t=b.options.toLineHeight(e.lineHeight,t),n=n?a*t+2*e.padding:0;this.isHorizontal()?(i.width=this.maxWidth,i.height=n):(i.width=n,i.height=this.maxHeight),this.width=i.width,this.height=i.height},afterFit:t,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this.ctx,e=b.valueOrDefault,n=this.options,i=y.global;if(n.display){var a,o,r,s=e(n.fontSize,i.defaultFontSize),l=e(n.fontStyle,i.defaultFontStyle),u=e(n.fontFamily,i.defaultFontFamily),l=b.fontString(s,l,u),d=b.options.toLineHeight(n.lineHeight,s),u=d/2+n.padding,s=0,h=this.top,c=this.left,f=this.bottom,g=this.right,m=(t.fillStyle=e(n.fontColor,i.defaultFontColor),t.font=l,this.isHorizontal()?(o=c+(g-c)/2,r=h+u,a=g-c):(o="left"===n.position?c+u:g-u,r=h+(f-h)/2,a=f-h,s=Math.PI*("left"===n.position?-.5:.5)),t.save(),t.translate(o,r),t.rotate(s),t.textAlign="center",t.textBaseline="middle",n.text);if(b.isArray(m))for(var p=0,v=0;vr.max)&&(r.max=t)})}),r.min=isFinite(r.min)&&!isNaN(r.min)?r.min:0,r.max=isFinite(r.max)&&!isNaN(r.max)?r.max:1,this.handleTickRangeOptions()},getTickLimit:function(){var t,e=this.options.ticks;return this.isHorizontal()?Math.min(e.maxTicksLimit||11,Math.ceil(this.width/50)):(t=h.valueOrDefault(e.fontSize,i.global.defaultFontSize),Math.min(e.maxTicksLimit||11,Math.ceil(this.height/(2*t))))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e=this.start,t=+this.getRightValue(t),n=this.end-e,n=this.isHorizontal()?this.left+this.width/n*(t-e):this.bottom-this.height/n*(t-e);return n},getValueForPixel:function(t){var e=this.isHorizontal(),n=e?this.width:this.height,e=(e?t-this.left:this.bottom-t)/n;return this.start+(this.end-this.start)*e},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",n,e)}},{25:25,34:34,45:45}],55:[function(t,e,n){"use strict";var u=t(45);e.exports=function(e){var t=u.noop;e.LinearScaleBase=e.Scale.extend({getRightValue:function(t){return"string"==typeof t?+t:e.Scale.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks,n=(e.beginAtZero&&(n=u.sign(t.min),i=u.sign(t.max),n<0&&i<0?t.max=0:0=t.max&&(n?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},getTickLimit:t,handleDirectionalChanges:t,buildTicks:function(){var t=this,e=t.options.ticks,n=t.getTickLimit(),n={maxTicks:Math.max(2,n),min:e.min,max:e.max,stepSize:u.valueOrDefault(e.fixedStepSize,e.stepSize)},n=t.ticks=function(t,e){var n,i=[],a=(n=t.stepSize&&0o.max)&&(o.max=t),0!=t&&(null===o.minNotZero||to.r&&(o.r=h.end,r.r=u),d.starto.b&&(o.b=d.end,r.b=u)}t.setReductions(a,o,r)}function i(t){var e=t.ctx,n=t.options,i=n.angleLines,a=n.pointLabels,o=(e.lineWidth=i.lineWidth,e.strokeStyle=i.color,t.getDistanceFromCenterForValue(n.ticks.reverse?t.min:t.max)),r=x(t);e.textBaseline="top";for(var s,l=b(t)-1;0<=l;l--)if(i.display&&(u=t.getPointPosition(l,o),e.beginPath(),e.moveTo(t.xCenter,t.yCenter),e.lineTo(u.x,u.y),e.stroke(),e.closePath()),a.display){var u=t.getPointPosition(l,o+5),d=_.valueAtIndexOrDefault(a.fontColor,l,y.defaultFontColor),d=(e.font=r.font,e.fillStyle=d,t.getIndexAngle(l)),d=_.toDegrees(d),h=(e.textAlign=0===(g=d)||180===g?"center":g<180?"left":"right",g=d,d=t._pointLabelSizes[l],s=u,90===g||270===g?s.y-=d.h/2:(270>1)-1]||null,o=t[i],!a)return{lo:null,hi:o};if(o[e]n))return{lo:a,hi:o};s=i-1}}return{lo:o,hi:null}}(t,e,n),o=a.lo?a.hi?a.lo:t[t.length-2]:t[0],a=a.lo?a.hi||t[t.length-1]:t[1],t=a[e]-o[e],n=t?(n-o[e])/t:0,e=(a[i]-o[i])*n;return o[i]+e}function O(t,e){var n=e.parser,e=e.parser||e.format;return"function"==typeof n?n(t):"string"==typeof t&&"string"==typeof e?D(t,e):!(t=t instanceof D?t:D(t)).isValid()&&"function"==typeof e?e(t):t}function I(t,e){var n;return!m.isNullOrUndef(t)&&(n=e.options.time,(e=O(e.getRightValue(t),n)).isValid())?(n.round&&e.startOf(n.round),e.valueOf()):null}function A(t){for(var e=P.indexOf(t)+1,n=P.length;e=P.indexOf(e);r--)if(a=P[r],C[a].common&&o.as(a)>=t.length)return a;return P[e?P.indexOf(e):0]}(y,p.minUnit,c.min,c.max),c._majorUnit=A(c._unit),c._table=function(t,e,n,i){if("linear"===i||!t.length)return[{time:e,pos:0},{time:n,pos:1}];for(var a,o,r,s=[],l=[e],u=0,d=t.length;u{let t=0;return()=>t++})();function P(t){return null==t}function O(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.slice(0,7)&&"Array]"===e.slice(-6)}function A(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}function p(t){return("number"==typeof t||t instanceof Number)&&isFinite(+t)}function g(t,e){return p(t)?t:e}function T(t,e){return void 0===t?e:t}const V=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:+t/e,B=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function d(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function k(t,e,i,s){let a,n,o;if(O(t))if(n=t.length,s)for(a=n-1;0<=a;a--)e.call(i,t[a],a);else for(a=0;at,x:t=>t.x,y:t=>t.y};function q(t){const e=t.split("."),i=[];let s="";for(const t of e)s+=t,s=s.endsWith("\\")?s.slice(0,-1)+".":(i.push(s),"");return i}function m(t,e){const i=X[e]||(X[e]=function(){const i=q(e);return t=>{for(const e of i){if(""===e)break;t=t&&t[e]}return t}}());return i(t)}function K(t){return t.charAt(0).toUpperCase()+t.slice(1)}const G=t=>void 0!==t,u=t=>"function"==typeof t,Z=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function J(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const S=Math.PI,_=2*S,Q=_+S,tt=Number.POSITIVE_INFINITY,et=S/180,D=S/2,it=S/4,st=2*S/3,r=Math.log10,y=Math.sign;function at(t,e,i){return Math.abs(t-e)t-e).pop(),e}function rt(t){return!isNaN(parseFloat(t))&&isFinite(t)}function lt(t,e){var i=Math.round(t);return i-e<=t&&t<=i+e}function ht(t,e,i){let s,a,n;for(s=0,a=t.length;s=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function bt(e,i,t){t=t||(t=>e[t]>1)?n=s:a=s;return{lo:n,hi:a}}const f=(i,s,a,t)=>bt(i,a,t?t=>{var e=i[t][s];return ei[t][s]bt(e,s,t=>e[t][i]>=s);function vt(t,e,i){let s=0,a=t.length;for(;ss&&t[a-1]>i;)a--;return 0{const i="_onData"+K(t),s=a[t];Object.defineProperty(a,t,{configurable:!0,enumerable:!1,value(...e){var t=s.apply(this,e);return a._chartjs.listeners.forEach(t=>{"function"==typeof t[i]&&t[i](...e)}),t}})}))}function Mt(e,t){var i=e._chartjs;if(i){const s=i.listeners,a=s.indexOf(t);-1!==a&&s.splice(a,1),0{delete e[t]}),delete e._chartjs)}}function wt(t){var e=new Set(t);return e.size===t.length?t:Array.from(e)}const kt="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function St(e,i){let s,a=!1;return function(...t){s=t,a||(a=!0,kt.call(window,()=>{a=!1,e.apply(i,s)}))}}function Pt(e,i){let s;return function(...t){return i?(clearTimeout(s),s=setTimeout(e,i,t)):e.apply(this,t),i}}const Dt=t=>"start"===t?"left":"end"===t?"right":"center",E=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,Ct=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;function Ot(t,e,i){var s=e.length;let a=0,n=s;if(t._sorted){const{iScale:o,_parsed:r}=t,l=o.axis,{min:h,max:c,minDefined:d,maxDefined:u}=o.getUserBounds();d&&(a=C(Math.min(f(r,l,h).lo,i?s:f(e,l,o.getPixelForValue(h)).lo),0,s-1)),n=u?C(Math.max(f(r,o.axis,c,!0).hi+1,i?0:f(e,l,o.getPixelForValue(c),!0).hi+1),a,s)-a:s-a}return{start:a,count:n}}function At(t){var{xScale:e,yScale:i,_scaleRanges:s}=t,a={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=a,!0;t=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,a),t}var l=new class{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(e,i,s,t){const a=i.listeners[t],n=i.duration;a.forEach(t=>t({chart:e,initial:i.initial,numSteps:n,currentStep:Math.min(s-i.start,n)}))}_refresh(){this._request||(this._running=!0,this._request=kt.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(o=Date.now()){let r=0;this._charts.forEach((s,a)=>{if(s.running&&s.items.length){const n=s.items;let t,e=n.length-1,i=!1;for(;0<=e;--e)(t=n[e])._active?(t._total>s.duration&&(s.duration=t._total),t.tick(o),i=!0):(n[e]=n[n.length-1],n.pop());i&&(a.draw(),this._notify(a,s,o,"progress")),n.length||(s.running=!1,this._notify(a,s,o,"complete"),s.initial=!1),r+=n.length}}),this._lastDate=o,0===r&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return 0Math.max(t,e._duration),0),this._refresh())}running(t){if(!this._running)return!1;t=this._charts.get(t);return!!(t&&t.running&&t.items.length)}stop(e){const i=this._charts.get(e);if(i&&i.items.length){const s=i.items;let t=s.length-1;for(;0<=t;--t)s[t].cancel();i.items=[],this._notify(e,i,Date.now(),"complete")}}remove(t){return this._charts.delete(t)}};function Tt(t){return t+.5|0}const Lt=(t,e,i)=>Math.max(Math.min(t,i),e);function Et(t){return Lt(Tt(2.55*t),0,255)}function Rt(t){return Lt(Tt(255*t),0,255)}function o(t){return Lt(Tt(t/2.55)/100,0,1)}function It(t){return Lt(Tt(100*t),0,100)}const n={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},zt=[..."0123456789ABCDEF"],Ft=t=>zt[15&t],Vt=t=>zt[(240&t)>>4]+zt[15&t],Bt=t=>(240&t)>>4==(15&t);const Wt=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Nt(i,t,s){const a=t*Math.min(s,1-s),e=(t,e=(t+i/30)%12)=>s-a*Math.max(Math.min(e-3,9-e,1),-1);return[e(0),e(8),e(4)]}function Ht(i,s,a){i=(t,e=(t+i/60)%6)=>a-a*s*Math.max(Math.min(e,4-e,1),0);return[i(5),i(3),i(1)]}function jt(t,e,i){const s=Nt(t,1,.5);let a;for(1t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Qt=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4);function te(e,i,s){if(e){let t=Yt(e);t[i]=Math.max(0,Math.min(t[i]+t[i]*s,0===i?360:1)),t=Ut(t),e.r=t[0],e.g=t[1],e.b=t[2]}}function ee(t,e){return t&&Object.assign(e||{},t)}function ie(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?3<=t.length&&(e={r:t[0],g:t[1],b:t[2],a:255},3>16&255,n>>8&255,255&n]}return t}()).transparent=[0,0,0,0]),(i=Gt[i.toLowerCase()])&&{r:i[0],g:i[1],b:i[2],a:4===i.length?i[3]:255})||se(t)),this._rgb=a,this._valid=!!a}get valid(){return this._valid}get rgb(){var t=ee(this._rgb);return t&&(t.a=o(t.a)),t}set rgb(t){this._rgb=ie(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${o(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):void 0;var t}hexString(){return this._valid?(t=this._rgb,e=t,e=Bt(e.r)&&Bt(e.g)&&Bt(e.b)&&Bt(e.a)?Ft:Vt,t?"#"+e(t.r)+e(t.g)+e(t.b)+((t=t.a)<255?e(t):""):void 0):void 0;var t,e}hslString(){if(this._valid){var t,e,i,s=this._rgb;if(s)return i=Yt(s),t=i[0],e=It(i[1]),i=It(i[2]),s.a<255?`hsla(${t}, ${e}%, ${i}%, ${o(s.a)})`:`hsl(${t}, ${e}%, ${i}%)`}}mix(t,e){if(t){const s=this.rgb,a=t.rgb;var t=void 0===e?.5:e,e=2*t-1,i=s.a-a.a,e=(1+(e*i==-1?e:(e+i)/(1+e*i)))/2,i=1-e;s.r=255&e*s.r+i*a.r+.5,s.g=255&e*s.g+i*a.g+.5,s.b=255&e*s.b+i*a.b+.5,s.a=t*s.a+(1-t)*a.a,this.rgb=s}return this}interpolate(t,e){return t&&(this._rgb=(i=this._rgb,t=t._rgb,e=e,s=Qt(o(i.r)),a=Qt(o(i.g)),n=Qt(o(i.b)),{r:Rt(Jt(s+e*(Qt(o(t.r))-s))),g:Rt(Jt(a+e*(Qt(o(t.g))-a))),b:Rt(Jt(n+e*(Qt(o(t.b))-n))),a:i.a+e*(t.a-i.a)})),this;var i,s,a,n}clone(){return new ae(this.rgb)}alpha(t){return this._rgb.a=Rt(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=Tt(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return te(this._rgb,2,t),this}darken(t){return te(this._rgb,2,-t),this}saturate(t){return te(this._rgb,1,t),this}desaturate(t){return te(this._rgb,1,-t),this}rotate(t){return e=this._rgb,t=t,(i=Yt(e))[0]=Xt(i[0]+t),i=Ut(i),e.r=i[0],e.g=i[1],e.b=i[2],this;var e,i}}function ne(t){return!(!t||"object"!=typeof t)&&("[object CanvasPattern]"===(t=t.toString())||"[object CanvasGradient]"===t)}function oe(t){return ne(t)?t:new ae(t)}function re(t){return ne(t)?t:new ae(t).saturate(.5).darken(.1).hexString()}const le=["x","y","borderWidth","radius","tension"],he=["color","borderColor","backgroundColor"],ce=new Map;function de(t,e,a){return function(t,e){e=a||{};var i=t+JSON.stringify(e);let s=ce.get(i);return s||(s=new Intl.NumberFormat(t,e),ce.set(i,s)),s}(e).format(t)}const ue={values:t=>O(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";var s=this.chart.options.locale;let a,n=t;if(1.8*i.length?ue.numeric.call(this,t,e,i):""}};var ge={formatters:ue};const fe=Object.create(null),pe=Object.create(null);function me(i,t){if(!t)return i;var s=t.split(".");for(let t=0,e=s.length;tt.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>re(e.backgroundColor),this.hoverBorderColor=(t,e)=>re(e.borderColor),this.hoverColor=(t,e)=>re(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(e)}set(t,e){return be(this,t,e)}get(t){return me(this,t)}describe(t,e){return be(pe,t,e)}override(t,e){return be(fe,t,e)}route(t,e,i,s){const a=me(this,t),n=me(this,i),o="_"+e;Object.defineProperties(a,{[o]:{value:a[e],writable:!0},[e]:{enumerable:!0,get(){var t=this[o],e=n[s];return A(t)?Object.assign({},e,t):T(t,e)},set(t){this[o]=t}}})}apply(t){t.forEach(t=>t(this))}}({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(t){t.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),t.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),t.set("animations",{colors:{type:"color",properties:he},numbers:{type:"number",properties:le}}),t.describe("animations",{_fallback:"animation"}),t.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}})},function(t){t.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(t){t.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,e)=>e.lineWidth,tickColor:(t,e)=>e.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:ge.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),t.route("scale.ticks","color","","color"),t.route("scale.grid","color","","borderColor"),t.route("scale.border","color","","borderColor"),t.route("scale.title","color","","color"),t.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t&&"dash"!==t}),t.describe("scales",{_fallback:"scale"}),t.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t})}]);function xe(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ve(t){let e=t.parentNode;return e=e&&"[object ShadowRoot]"===e.toString()?e.host:e}function _e(t,e,i){let s;return"string"==typeof t?(s=parseInt(t,10),-1!==t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}const ye=t=>t.ownerDocument.defaultView.getComputedStyle(t,null);function Me(t,e){return ye(t).getPropertyValue(e)}const we=["top","right","bottom","left"];function ke(e,i,s){const a={};s=s?"-"+s:"";for(let t=0;t<4;t++){var n=we[t];a[n]=parseFloat(e[i+"-"+n+s])||0}return a.width=a.left+a.right,a.height=a.top+a.bottom,a}function Se(t,e){if("native"in t)return t;var{canvas:i,currentDevicePixelRatio:s}=e,a=ye(i),n="border-box"===a.boxSizing,o=ke(a,"padding"),a=ke(a,"border","width"),{x:t,y:r,box:l}=function(t,e){var i,s=t.touches,s=s&&s.length?s[0]:t,{offsetX:a,offsetY:n}=s;let o,r,l=!1;if(i=n,t=t.target,!(0Math.round(10*t)/10;function De(t,e,i,s){var a=ye(t),n=ke(a,"margin"),o=_e(a.maxWidth,t,"clientWidth")||tt,r=_e(a.maxHeight,t,"clientHeight")||tt,t=function(t,e,i){let s,a;if(void 0===e||void 0===i){const n=ve(t);if(n){const t=n.getBoundingClientRect(),o=ye(n),r=ke(o,"border","width"),l=ke(o,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=_e(o.maxWidth,n,"clientWidth"),a=_e(o.maxHeight,n,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||tt,maxHeight:a||tt}}(t,e,i);let{width:l,height:h}=t;if("content-box"===a.boxSizing){const t=ke(a,"border","width"),e=ke(a,"padding");l-=e.width+t.width,h-=e.height+t.height}return l=Math.max(0,l-n.width),h=Math.max(0,s?l/s:h-n.height),l=Pe(Math.min(l,o,t.maxWidth)),h=Pe(Math.min(h,r,t.maxHeight)),l&&!h&&(h=Pe(l/2)),(void 0!==e||void 0!==i)&&s&&t.height&&h>t.height&&(h=t.height,l=Pe(Math.floor(h*s))),{width:l,height:h}}function Ce(t,e,i){var e=e||1,s=Math.floor(t.height*e),a=Math.floor(t.width*e);t.height=Math.floor(t.height),t.width=Math.floor(t.width);const n=t.canvas;return n.style&&(i||!n.style.height&&!n.style.width)&&(n.style.height=t.height+"px",n.style.width=t.width+"px"),(t.currentDevicePixelRatio!==e||n.height!==s||n.width!==a)&&(t.currentDevicePixelRatio=e,n.height=s,n.width=a,t.ctx.setTransform(e,0,0,e,0,0),!0)}var Oe=function(){let t=!1;try{var e={get passive(){return!(t=!0)}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function Ae(t,e){const i=Me(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function Te(t){return!t||P(t.size)||P(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Le(t,e,i,s,a){let n=e[a];return n||(n=e[a]=t.measureText(a).width,i.push(a)),s=n>s?n:s}function Ee(t,e,i,s){let a=(s=s||{}).data=s.data||{},n=s.garbageCollect=s.garbageCollect||[],o=(s.font!==e&&(a=s.data={},n=s.garbageCollect=[],s.font=e),t.save(),t.font=e,0);var r=i.length;let l,h,c,d,u;for(l=0;li.length){for(l=0;le.left-i&&t.xe.top-i&&t.yr[0]){const i=t||r;void 0===e&&(e=ti("_fallback",r));t={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:r,_rootScopes:i,_fallback:e,_getTarget:a,override:t=>Ye([t,...r],l,i,e)};return new Proxy(t,{deleteProperty:(t,e)=>(delete t[e],delete t._keys,delete r[0][e],!0),get:(n,o)=>Ke(n,o,()=>{var t,e=o,i=r,s=n;for(const a of l)if(t=ti(Xe(a,e),i),void 0!==t)return qe(e,t)?Je(i,s,e,t):t}),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(r[0]),has:(t,e)=>ei(t).includes(e),ownKeys:t=>ei(t),set(t,e,i){const s=t._storage||(t._storage=a());return t[e]=s[e]=i,delete t._keys,!0}})}function $e(s,e,i,a){var t={_cacheable:!1,_proxy:s,_context:e,_subProxy:i,_stack:new Set,_descriptors:Ue(s,a),setContext:t=>$e(s,t,i,a),override:t=>$e(s.override(t),e,i,a)};return new Proxy(t,{deleteProperty:(t,e)=>(delete t[e],delete s[e],!0),get:(r,h,c)=>Ke(r,h,()=>{{var l=r,e=h,i=c;const{_proxy:s,_context:a,_subProxy:n,_descriptors:o}=l;let t=s[e];return O(t=u(t)&&o.isScriptable(e)?function(t,e,i){const{_proxy:s,_context:a,_subProxy:n,_stack:o}=l;if(o.has(t))throw new Error("Recursion detected: "+Array.from(o).join("->")+"->"+t);o.add(t);let r=e(a,n||i);return o.delete(t),r=qe(t,r)?Je(s._scopes,s,t,r):r}(e,t,i):t)&&t.length&&(t=function(t,e,i,s){const{_proxy:a,_context:n,_subProxy:o,_descriptors:r}=i;if(void 0!==n.index&&s(t))return e[n.index%e.length];if(A(e[0])){const i=e,s=a._scopes.filter(t=>t!==i);e=[];for(const A of i){const i=Je(s,a,t,A);e.push($e(i,n,o&&o[t],r))}}return e}(e,t,l,o.isIndexable)),t=qe(e,t)?$e(t,a,n&&n[e],o):t}}),getOwnPropertyDescriptor:(t,e)=>t._descriptors.allKeys?Reflect.has(s,e)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(s,e),getPrototypeOf:()=>Reflect.getPrototypeOf(s),has:(t,e)=>Reflect.has(s,e),ownKeys:()=>Reflect.ownKeys(s),set:(t,e,i)=>(s[e]=i,delete t[e],!0)})}function Ue(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:a=e.allKeys}=t;return{allKeys:a,scriptable:i,indexable:s,isScriptable:u(i)?i:()=>i,isIndexable:u(s)?s:()=>s}}const Xe=(t,e)=>t?t+K(e):e,qe=(t,e)=>A(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function Ke(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];i=i();return t[e]=i}function Ge(t,e,i){return u(t)?t(e,i):t}function Ze(t,e,i,s,a){for(const r of e){n=i,o=r;const e=!0===n?o:"string"==typeof n?m(o,n):void 0;if(e){t.add(e);o=Ge(e._fallback,i,a);if(void 0!==o&&o!==i&&o!==s)return o}else if(!1===e&&void 0!==s&&i!==s)return null}var n,o;return!1}function Je(t,s,a,n){const e=s._rootScopes,i=Ge(s._fallback,a,n),o=[...t,...e],r=new Set;r.add(n);t=Qe(r,o,a,i||a,n);return null!==t&&(void 0===i||i===a||null!==Qe(r,o,i,t,n))&&Ye(Array.from(r),[""],e,i,()=>{{var t=a,e=n;const i=s._getTarget();return t in i||(i[t]={}),O(t=i[t])&&A(e)?e:t||{}}})}function Qe(t,e,i,s,a){for(;i;)i=Ze(t,e,i,s,a);return i}function ti(t,e){for(const i of e)if(i){const e=i[t];if(void 0!==e)return e}}function ei(t){let e=t._keys;return e=e||(t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter(t=>!t.startsWith("_")))e.add(t);return Array.from(e)}(t._scopes))}function ii(t,e,i,s){const a=t["iScale"],{key:n="r"}=this._parsing,o=new Array(s);let r,l,h,c;for(r=0,l=s;re"x"===t?"y":"x";function oi(t,e,i,s){var t=t.skip?e:t,a=e,e=i.skip?e:i,i=gt(a,t),n=gt(e,a);let o=i/(i+n),r=n/(i+n);o=isNaN(o)?0:o,r=isNaN(r)?0:r;i=s*o,n=s*r;return{previous:{x:a.x-i*(e.x-t.x),y:a.y-i*(e.y-t.y)},next:{x:a.x+n*(e.x-t.x),y:a.y+n*(e.y-t.y)}}}function ri(t,n="x"){const e=ni(n),i=t.length,r=Array(i).fill(0),l=Array(i);let s,a,o,h=ai(t,0);for(s=0;s!t.skip)),"monotone"===e.cubicInterpolationMode)ri(o,t);else{let t=i?o[o.length-1]:o[0];for(s=0,a=o.length;s0===t||1===t,di=(t,e,i)=>-Math.pow(2,10*--t)*Math.sin((t-e)*_/i),ui=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*_/i)+1,gi={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>--t*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-(--t*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>--t*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*D),easeOutSine:t=>Math.sin(t*D),easeInOutSine:t=>-.5*(Math.cos(S*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>ci(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>1<=t?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1- --t*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>ci(t)?t:di(t,.075,.3),easeOutElastic:t=>ci(t)?t:ui(t,.075,.3),easeInOutElastic(t){return ci(t)?t:t<.5?.5*di(2*t,.1125,.45):.5+.5*ui(2*t-1,.1125,.45)},easeInBack(t){return t*t*(2.70158*t-1.70158)},easeOutBack(t){return--t*t*(2.70158*t+1.70158)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-gi.easeOutBounce(1-t),easeOutBounce(t){var e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*gi.easeInBounce(2*t):.5*gi.easeOutBounce(2*t-1)+.5};function fi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function pi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:("middle"===s?i<.5?t:e:"after"===s?i<1?t:e:0+t||0;function yi(e,i){const t={},s=A(i),a=s?Object.keys(i):i,n=A(e)?s?t=>T(e[t],e[i[t]]):t=>e[t]:()=>e;for(const e of a)t[e]=_i(n(e));return t}function Mi(t){return yi(t,{top:"y",right:"x",bottom:"y",left:"x"})}function wi(t){return yi(t,["topLeft","topRight","bottomLeft","bottomRight"])}function I(t){const e=Mi(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function z(t,e){e=e||R.font;let i=T((t=t||{}).size,e.size),s=("string"==typeof i&&(i=parseInt(i,10)),T(t.style,e.style));s&&!(""+s).match(xi)&&(console.warn('Invalid font style specified: "'+s+'"'),s=void 0);const a={family:T(t.family,e.family),lineHeight:vi(T(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:T(t.weight,e.weight),string:""};return a.string=Te(a),a}function ki(t,e,i,s){let a,n,o,r=!0;for(a=0,n=t.length;ai&&0===t?0:t+e;return{min:a(t,-Math.abs(e)),max:a(s,e)}}function Pi(t,e){return Object.assign(Object.create(t),e)}function Di(t,e,i){return t?(s=e,a=i,{x:t=>s+s+a-t,setWidth(t){a=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t};var s,a}function Ci(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(s=[(i=t.canvas.style).getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function Oi(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Ai(t){return"angle"===t?{between:pt,compare:ft,normalize:v}:{between:c,compare:(t,e)=>t-e,normalize:t=>t}}function Ti({start:t,end:e,count:i,loop:s,style:a}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:a}}function Li(t,i,g){if(!g)return[t];const{property:s,start:a,end:n}=g,o=i.length,{compare:r,between:l,normalize:h}=Ai(s),{start:c,end:d,loop:u,style:f}=function(t,e){const{property:i,start:s,end:a}=g,{between:n,normalize:o}=Ai(i),r=e.length;let l,h,{start:c,end:d,loop:u}=t;if(u){for(c+=r,d+=r,l=0,h=r;ls&&t[a%e].skip;)a--;return a%=e,{start:s,end:a}}(i,s,a);return Ii(t,!0===n?[{start:o,end:r,loop:a}]:function(t,e,i,s){const a=t.length,n=[];let o,r=e,l=t[e];for(o=e+1;o<=i;++o){const i=t[o%a];i.skip||i.stop?l.skip||(s=!1,n.push({start:e%a,end:(o-1)%a,loop:s}),e=r=i.stop?o:null):(r=o,l.skip&&(e=o)),l=i}return null!==r&&n.push({start:e%a,end:r%a,loop:s}),n}(i,o,r{t[r](s[a],n)&&(o.push({element:t,datasetIndex:e,index:i}),l=l||t.inRange(s.x,s.y,n))}),e&&!l?[]:o}var Hi={evaluateInteractionItems:Vi,modes:{index(t,e,i,s){const a=Se(e,t),n=i.axis||"x",o=i.includeInvisible||!1,r=i.intersect?Bi(t,a,n,s,o):Wi(t,a,n,!1,s,o),l=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach(t=>{var e=r[0].index,i=t.data[e];i&&!i.skip&&l.push({element:i,datasetIndex:t.index,index:e})}),l):[]},dataset(t,e,i,s){var e=Se(e,t),a=i.axis||"xy",n=i.includeInvisible||!1;let o=i.intersect?Bi(t,e,a,s,n):Wi(t,e,a,!1,s,n);if(0Bi(t,Se(e,t),i.axis||"xy",s,i.includeInvisible||!1),nearest(t,e,i,s){var e=Se(e,t),a=i.axis||"xy",n=i.includeInvisible||!1;return Wi(t,e,a,i.intersect,s,n)},x:(t,e,i,s)=>Ni(t,Se(e,t),"x",i.intersect,s),y:(t,e,i,s)=>Ni(t,Se(e,t),"y",i.intersect,s)}};const ji=["left","top","right","bottom"];function Yi(t,e){return t.filter(t=>t.pos===e)}function $i(t,e){return t.filter(t=>-1===ji.indexOf(t.pos)&&t.box.axis===e)}function Ui(t,s){return t.sort((t,e)=>{var i=s?e:t,t=s?t:e;return i.weight===t.weight?i.index-t.index:i.weight-t.weight})}function Xi(t,e,i,s){return Math.max(t[i],e[i])+Math.max(t[s],e[s])}function qi(t,e){t.top=Math.max(t.top,e.top),t.left=Math.max(t.left,e.left),t.bottom=Math.max(t.bottom,e.bottom),t.right=Math.max(t.right,e.right)}function Ki(t,e,i,s){const a=[];let n,o,r,l,h,c;for(n=0,o=t.length,h=0;n{s[t]=Math.max(e[t],i[t])}),s}}(r.horizontal,e));const{same:o,other:d}=function(t,e,i,s){const{pos:a,box:n}=i,o=t.maxPadding;if(!A(a)){i.size&&(t[a]-=i.size);const e=s[i.stack]||{size:0,count:1};e.size=Math.max(e.size,i.horizontal?n.height:n.width),i.size=e.size/e.count,t[a]+=i.size}n.getPadding&&qi(o,n.getPadding());var s=Math.max(0,e.outerWidth-Xi(o,t,"left","right")),e=Math.max(0,e.outerHeight-Xi(o,t,"top","bottom")),r=s!==t.w,l=e!==t.h;return t.w=s,t.h=e,i.horizontal?{same:r,other:l}:{same:l,other:r}}(e,i,r,s);h|=o&&a.length,c=c||d,l.fullSize||a.push(r)}return h&&Ki(a,e,i,s)||c}function Gi(t,e,i,s,a){t.top=i,t.left=e,t.right=e+s,t.bottom=i+a,t.width=s,t.height=a}function Zi(t,e,i,s){var a=i.padding;let{x:n,y:o}=e;for(const r of t){const t=r.box,l=s[r.stack]||{count:1,placed:0,weight:1},h=r.stackWeight/l.weight||1;if(r.horizontal){const s=e.w*h,n=l.size||t.height;G(l.start)&&(o=l.start),t.fullSize?Gi(t,a.left,o,i.outerWidth-a.right-a.left,n):Gi(t,e.left+l.placed,o,s,n),l.start=o,l.placed+=s,o=t.bottom}else{const s=e.h*h,o=l.size||t.width;G(l.start)&&(n=l.start),t.fullSize?Gi(t,n,a.top,o,i.outerHeight-a.bottom-a.top):Gi(t,n,e.top+l.placed,o,s),l.start=n,l.placed+=s,n=t.right}}e.x=n,e.y=o}var a={addBox(t,e){t.boxes||(t.boxes=[]),e.fullSize=e.fullSize||!1,e.position=e.position||"top",e.weight=e.weight||0,e._layers=e._layers||function(){return[{z:0,draw(t){e.draw(t)}}]},t.boxes.push(e)},removeBox(t,e){e=t.boxes?t.boxes.indexOf(e):-1;-1!==e&&t.boxes.splice(e,1)},configure(t,e,i){e.fullSize=i.fullSize,e.position=i.position,e.weight=i.weight},update(l,t,e,i){if(l){const o=I(l.options.layout.padding),r=Math.max(t-o.width,0),h=Math.max(e-o.height,0),c=function(){const t=function(t){const e=[];let i,s,a,n,o,r;for(i=0,s=(t||[]).length;it.box.fullSize),!0),i=Ui(Yi(t,"left"),!0),s=Ui(Yi(t,"right")),a=Ui(Yi(t,"top"),!0),n=Ui(Yi(t,"bottom")),o=$i(t,"x"),r=$i(t,"y");return{fullSize:e,leftAndTop:i.concat(a),rightAndBottom:s.concat(r).concat(n).concat(o),chartArea:Yi(t,"chartArea"),vertical:i.concat(s).concat(r),horizontal:a.concat(n).concat(o)}}(),d=c.vertical,u=c.horizontal;k(l.boxes,t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()});var s=d.reduce((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1,0)||1,t=Object.freeze({outerWidth:t,outerHeight:e,padding:o,availableWidth:r,availableHeight:h,vBoxMaxWidth:r/2/s,hBoxMaxHeight:h/2}),e=Object.assign({},o);qi(e,I(i));const g=Object.assign({maxPadding:e,w:r,h:h,x:o.left,y:o.top},o),f=function(t,e){var i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:a}=i;if(t&&ji.includes(s)){const n=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});n.count++,n.weight+=a}}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:a}=e;let n,o,r;for(n=0,o=t.length;n{const e=t.box;Object.assign(e,l.chartArea),e.update(g.w,g.h,{left:0,top:0,right:0,bottom:0})})}}};class Ji{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,s){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,s?Math.floor(e/s):i)}}isAttached(t){return!0}updateConfig(t){}}class Qi extends Ji{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const ts="$chartjs",es={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},is=t=>null===t||""===t,ss=!!Oe&&{passive:!0};function as(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function ns(t,e,i){const s=t.canvas,a=new MutationObserver(t=>{let e=!1;for(const i of t)e=e||as(i.addedNodes,s),e=e&&!as(i.removedNodes,s);e&&i()});return a.observe(document,{childList:!0,subtree:!0}),a}function os(t,e,i){const s=t.canvas,a=new MutationObserver(t=>{let e=!1;for(const i of t)e=e||as(i.removedNodes,s),e=e&&!as(i.addedNodes,s);e&&i()});return a.observe(document,{childList:!0,subtree:!0}),a}const rs=new Map;let ls=0;function hs(){const i=window.devicePixelRatio;i!==ls&&(ls=i,rs.forEach((t,e)=>{e.currentDevicePixelRatio!==i&&t()}))}function cs(t,e,s){const i=t.canvas,a=i&&ve(i);if(a){const o=St((t,e)=>{var i=a.clientWidth;s(t,e),i{var t=t[0],e=t.contentRect.width,t=t.contentRect.height;0===e&&0===t||o(e,t)});return r.observe(a),t=t,n=o,rs.size||window.addEventListener("resize",hs),rs.set(t,n),r;var n}}function ds(t,e,i){i&&i.disconnect(),"resize"===e&&(i=t,rs.delete(i),rs.size||window.removeEventListener("resize",hs))}function us(e,t,i){var s=e.canvas,a=St(t=>{null!==e.ctx&&i(function(t,e){var i=es[t.type]||t.type,{x:s,y:a}=Se(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==a?a:null}}(t,e))},e);return s.addEventListener(t,a,ss),a}class gs extends Ji{acquireContext(t,e){var i=t&&t.getContext&&t.getContext("2d");{if(i&&i.canvas===t){{var s=e;const a=t.style,n=t.getAttribute("height"),o=t.getAttribute("width");if(t[ts]={initial:{height:n,width:o,style:{display:a.display,height:a.height,width:a.width}}},a.display=a.display||"block",a.boxSizing=a.boxSizing||"border-box",is(o)){const s=Ae(t,"width");void 0!==s&&(t.width=s)}if(is(n))if(""===t.style.height)t.height=t.width/(s||2);else{const s=Ae(t,"height");void 0!==s&&(t.height=s)}}return i}return null}}releaseContext(t){const i=t.canvas;if(!i[ts])return!1;const s=i[ts].initial,e=(["height","width"].forEach(t=>{var e=s[t];P(e)?i.removeAttribute(t):i.setAttribute(t,e)}),s.style||{});return Object.keys(e).forEach(t=>{i.style[t]=e[t]}),i.width=i.width,delete i[ts],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),a={attach:ns,detach:os,resize:cs}[e]||us;s[e]=a(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];s&&(({attach:ds,detach:ds,resize:ds}[e]||function(t,e,i){t.canvas.removeEventListener(e,i,ss)})(t,e,s),i[e]=void 0)}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return De(t,e,i,s)}isAttached(t){t=ve(t);return!(!t||!t.isConnected)}}function fs(t){return!xe()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?Qi:gs}Oe=Object.freeze({__proto__:null,BasePlatform:Ji,BasicPlatform:Qi,DomPlatform:gs,_detectPlatform:fs});const ps="transparent",ms={boolean:(t,e,i)=>.5t+(e-t)*i};class bs{constructor(t,e,i,s){var a=e[i],a=(s=ki([t.to,s,a,t.from]),ki([t.from,a,s]));this._active=!0,this._fn=t.fn||ms[t.type||typeof a],this._easing=gi[t.easing]||gi.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=a,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){var s,a,n;this._active&&(this._notify(!1),s=this._target[this._prop],a=i-this._start,n=this._duration-a,this._start=i,this._duration=Math.floor(Math.max(n,t.duration)),this._total+=a,this._loop=!!t.loop,this._to=ki([t.to,e,s,t.from]),this._from=ki([t.from,s,e]))}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){var t=t-this._start,e=this._duration,i=this._prop,s=this._from,a=this._loop,n=this._to;let o;if(this._active=s!==n&&(a||t{i.push({res:t,rej:e})})}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t{const t=s[e];if(A(t)){const i={};for(const s of a)i[s]=t[s];(O(t.properties)&&t.properties||[e]).forEach(t=>{t!==e&&n.has(t)||n.set(t,i)})}})}}_animateOptions(t,e){const i=e.options,s=function(e,i){if(i){let t=e.options;if(t)return t.$shared&&(e.options=t=Object.assign({},t,{$shared:!1,$animations:{}})),t;e.options=i}}(t,i);if(!s)return[];e=this._createAnimations(s,i);return i.$shared&&function(e,t){const i=[],s=Object.keys(t);for(let t=0;t{t.options=i},()=>{}),e}_createAnimations(e,i){const s=this._properties,a=[],n=e.$animations||(e.$animations={}),t=Object.keys(i),o=Date.now();let r;for(r=t.length-1;0<=r;--r){const c=t[r];if("$"!==c.charAt(0))if("options"===c)a.push(...this._animateOptions(e,i));else{var l=i[c];let t=n[c];var h=s.get(c);if(t){if(h&&t.active()){t.update(h,l,o);continue}t.cancel()}h&&h.duration?(n[c]=t=new bs(h,e,c,l),a.push(t)):e[c]=l}}return a}update(t,e){{if(0!==this._properties.size)return(t=this._createAnimations(t,e)).length?(l.add(this._chart,t),!0):void 0;Object.assign(t,e)}}}function vs(t,e){var t=t&&t.options||{},i=t.reverse,s=void 0===t.min?e:0,t=void 0===t.max?e:0;return{start:i?t:s,end:i?s:t}}function _s(t,e){const i=[],s=t._getSortedDatasetMetas(e);let a,n;for(a=0,n=s.length;ai[t].axis===e).shift()}function Ps(t,e){var i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i],void 0!==e[s]._visualValues&&void 0!==e[s]._visualValues[i]&&delete e[s]._visualValues[i]}}}const Ds=t=>"reset"===t||"none"===t,Cs=(t,e)=>e?t:Object.assign({},t);class Os{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Ms(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&Ps(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,a=e.xAxisID=T(i.xAxisID,Ss(t,"x")),n=e.yAxisID=T(i.yAxisID,Ss(t,"y")),o=e.rAxisID=T(i.rAxisID,Ss(t,"r")),r=e.indexAxis,l=e.iAxisID=s(r,a,n,o),h=e.vAxisID=s(r,n,a,o);e.xScale=this.getScaleForId(a),e.yScale=this.getScaleForId(n),e.rScale=this.getScaleForId(o),e.iScale=this.getScaleForId(l),e.vScale=this.getScaleForId(h)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){var e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){var t=this._cachedMeta;this._data&&Mt(this._data,this),t._stacked&&Ps(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(A(e))this._data=function(t){const e=Object.keys(t),i=new Array(e.length);let s,a,n;for(s=0,a=e.length;snull===l[o]||d&&l[o]t||cthis.getContext(i,s,e),c);return g.$shared&&(g.$shared=r,a[n]=Object.freeze(Cs(g,r))),g}_resolveAnimations(t,e,i){const s=this.chart,a=this._cachedDataOpts,n="animation-"+e,o=a[n];if(o)return o;let r;if(!1!==s.options.animation){const s=this.chart.config,a=s.datasetAnimationScopeKeys(this._type,e),n=s.getOptionScopes(this.getDataset(),a);r=s.createResolver(n,this.getContext(t,i,e))}t=new xs(s,r&&r.animations);return r&&r._cacheable&&(a[n]=Object.freeze(t)),t}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||Ds(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){var t=this.resolveDataElementOptions(t,e),i=this._sharedOptions,s=this.getSharedOptions(t),i=this.includeOptions(e,s)||s!==i;return this.updateSharedOptions(s,e,t),{sharedOptions:s,includeOptions:i}}updateElement(t,e,i,s){Ds(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!Ds(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;var a=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(a)||a})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){var t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){var t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];var s=i.length,a=e.length,n=Math.min(a,s);n&&this.parse(0,n),s{for(t.length+=e,o=t.length-1;o>=n;o--)t[o]=t[o-e]};for(r(a),o=t;o{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]}),s}}function As(t,e,i,s,a){var n=T(s,0),o=Math.min(T(a,t.length),t.length);let r,l,h,c=0;for(i=Math.ceil(i),a&&(i=(r=a-s)/Math.floor(r/i)),h=n;h<0;)c++,h=Math.round(n+c*i);for(l=Math.max(n,0);l"top"===e||"left"===e?t[e]+i:t[e]-i,Ls=(t,e)=>Math.min(e||t,t);function Es(t,e){const i=[],s=t.length/e,a=t.length;let n=0;for(;nn?n:a,n=o&&a>n?a:n,{min:g(a,g(n,a)),max:g(n,g(a,n))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(t,e,i){var{beginAtZero:s,grace:a,ticks:n}=this.options,o=n.sampleSize,t=(this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=Si(this,a,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks(),os)return i}return Math.max(s,1)}(n,s,a);if(0{const e=t.gc,i=e.length/2;let s;if(y({width:n[t]||0,height:o[t]||0});return{first:w(0),last:w(e-1),widest:w(i),highest:w(M),widths:n,heights:o}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){var e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);t=this._startPixel+t*this._length;return mt(this._alignToPixels?Re(this.chart,t,0):t)}getDecimalForPixel(t){t=(t-this._startPixel)/this._length;return this._reversePixels?1-t:t}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){var{min:t,max:e}=this;return t<0&&e<0?e:0o+1e-6)))return l}(this,b,l))&&(v=Re(s,x,A),h?_=M=k=P=v:y=w=S=D=v,u.push({tx1:_,ty1:y,tx2:M,ty2:w,x1:k,y1:S,x2:P,y2:D,width:A,color:o,borderDash:T,borderDashOffset:c,tickWidth:d,tickColor:g,tickBorderDash:f,tickBorderDashOffset:p}))}return this._ticksLength=c,this._borderValue=m,u}_computeLabelItems(s){const a=this.axis,n=this.options,{position:o,ticks:e}=n,r=this.isHorizontal(),l=this.ticks,{align:h,crossAlign:c,padding:t,mirror:d}=e,i=Rs(n.grid),u=i+t,g=d?-t:u,f=-L(this.labelRotation),p=[];let m,b,x,v,_,y,M,w,k,S,P,D="middle";if("top"===o)_=this.bottom-g,y=this._getXAxisLabelAlignment();else if("bottom"===o)_=this.top+g,y=this._getXAxisLabelAlignment();else if("left"===o){const s=this._getYAxisLabelAlignment(i);y=s.textAlign,v=s.x}else if("right"===o){const s=this._getYAxisLabelAlignment(i);y=s.textAlign,v=s.x}else if("x"===a){if("center"===o)_=(s.top+s.bottom)/2+u;else if(A(o)){const s=Object.keys(o)[0],a=o[s];_=this.chart.scales[s].getPixelForValue(a)+u}y=this._getXAxisLabelAlignment()}else if("y"===a){if("center"===o)v=(s.left+s.right)/2-u;else if(A(o)){const s=Object.keys(o)[0],a=o[s];v=this.chart.scales[s].getPixelForValue(a)}y=this._getYAxisLabelAlignment(i).textAlign}"y"===a&&("start"===h?D="top":"end"===h&&(D="bottom"));var C=this._getLabelSizes();for(m=0,b=l.length;mt.value===e);return 0<=i?t.setContext(this.getContext(i)).lineWidth:0}drawGrid(t){const e=this.options.grid,s=this.ctx,i=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let a,n;var o=(t,e,i)=>{i.width&&i.color&&(s.save(),s.lineWidth=i.width,s.strokeStyle=i.color,s.setLineDash(i.borderDash||[]),s.lineDashOffset=i.borderDashOffset,s.beginPath(),s.moveTo(t.x,t.y),s.lineTo(e.x,e.y),s.stroke(),s.restore())};if(e.display)for(a=0,n=i.length;a{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:t,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let a,n;for(a=0,n=e.length;a{const e=t.split("."),i=e.pop(),s=[r].concat(e).join("."),a=l[t].split("."),n=a.pop(),o=a.join(".");R.route(s,i,o,n)})),e.descriptors&&R.describe(s,e.descriptors),this.override&&R.override(t.id,t.overrides)),h;throw new Error("class does not have id: "+t)}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in R[s]&&(delete R[s][i],this.override&&delete fe[i])}}var b=new class{constructor(){this.controllers=new Fs(Os,"datasets",!0),this.elements=new Fs(e,"elements"),this.plugins=new Fs(Object,"plugins"),this.scales=new Fs(zs,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(i,t,s){[...t].forEach(t=>{const e=s||this._getRegistryForType(t);s||e.isForType(t)||e===this.plugins&&t.id?this._exec(i,e,t):k(t,t=>{var e=s||this._getRegistryForType(t);this._exec(i,e,t)})})}_exec(t,e,i){var s=K(t);d(i["before"+s],[],i),e[t](i),d(i["after"+s],[],i)}_getRegistryForType(e){for(let t=0;tt.filter(e=>!i.some(t=>e.plugin.id===t.plugin.id));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function Bs(t,e){var i=R.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function Ws(t){if("x"===t||"y"===t||"r"===t)return t}function Ns(t,...e){if(Ws(t))return t;for(const s of e){const e=s.axis||("top"===(i=s.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||1{var e=r[t];if(!A(e))return console.error("Invalid scale configuration for scale: "+t);if(e._proxy)return console.warn("Ignoring resolver passed as options for scale: "+t);const i=Ns(t,e,function(e,t){if(t.data&&t.data.datasets){t=t.data.datasets.filter(t=>t.xAxisID===e||t.yAxisID===e);if(t.length)return Hs(e,"x",t[0])||Hs(e,"y",t[0])}return{}}(t,o),R.scales[e.type]),s=i===l?"_index_":"_value_",a=n.scales||{};h[t]=$(Object.create(null),[{axis:i},e,a[i],a[s]])}),o.data.datasets.forEach(s=>{const t=s.type||o.type,a=s.indexAxis||Bs(t,e),n=(fe[t]||{}).scales||{};Object.keys(n).forEach(t=>{var e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,a),i=s[e+"AxisID"]||e;h[i]=h[i]||Object.create(null),$(h[i],[{axis:e},r[i],n[t]])})}),Object.keys(h).forEach(t=>{t=h[t];$(t,[R.scales[t.type],R.scale])}),h}(t,e)}function Ys(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const $s=new Map,Us=new Set;function Xs(t,e){let i=$s.get(t);return i||(i=e(),$s.set(t,i),Us.add(i)),i}const qs=(t,e,i)=>{e=m(e,i);void 0!==e&&t.add(e)};class Ks{constructor(t){this._config=((t=(t=t)||{}).data=Ys(t.data),js(t),t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=Ys(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){var t=this._config;this.clearCache(),js(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return Xs(t,()=>[["datasets."+t,""]])}datasetAnimationScopeKeys(t,e){return Xs(t+".transition."+e,()=>[[`datasets.${t}.transitions.`+e,"transitions."+e],["datasets."+t,""]])}datasetElementScopeKeys(t,e){return Xs(t+"-"+e,()=>[[`datasets.${t}.elements.`+e,"datasets."+t,"elements."+e,""]])}pluginScopeKeys(t){const e=t.id;return Xs(this.type+"-plugin-"+e,()=>[["plugins."+e,...t.additionalOptionScopes||[]]])}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(e,t,i){const{options:s,type:a}=this,n=this._cachedScopes(e,i),o=n.get(t);if(o)return o;const r=new Set,l=(t.forEach(t=>{e&&(r.add(e),t.forEach(t=>qs(r,e,t))),t.forEach(t=>qs(r,s,t)),t.forEach(t=>qs(r,fe[a]||{},t)),t.forEach(t=>qs(r,R,t)),t.forEach(t=>qs(r,pe,t))}),Array.from(r));return 0===l.length&&l.push(Object.create(null)),Us.has(t)&&n.set(t,l),l}chartOptionScopes(){var{options:t,type:e}=this;return[t,fe[e]||{},R.datasets[e]||{},{type:e},R,pe]}resolveNamedOptions(t,e,i,s=[""]){const a={$shared:!0},{resolver:n,subPrefixes:o}=Gs(this._resolverCache,t,s);let r=n;!function(t,e){const{isScriptable:i,isIndexable:s}=Ue(t);for(const a of e){const e=i(a),n=s(a),o=(n||e)&&t[a];if(e&&(u(o)||Zs(o))||n&&O(o))return 1}}(n,e)||(a.$shared=!1,r=$e(n,i=u(i)?i():i,this.createResolver(t,i,o)));for(const t of e)a[t]=r[t];return a}createResolver(t,e,i=[""],s){t=Gs(this._resolverCache,t,i).resolver;return A(e)?$e(t,e,void 0,s):t}}function Gs(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));t=i.join();let a=s.get(t);return a||(a={resolver:Ye(e,i),subPrefixes:i.filter(t=>!t.toLowerCase().includes("hover"))},s.set(t,a)),a}const Zs=i=>A(i)&&Object.getOwnPropertyNames(i).reduce((t,e)=>t||u(i[e]),!1),Js=["top","bottom","left","right","chartArea"];function Qs(t,e){return"top"===t||"bottom"===t||-1===Js.indexOf(t)&&"x"===e}function ta(i,s){return function(t,e){return t[i]===e[i]?t[s]-e[s]:t[i]-e[i]}}function ea(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),d(i&&i.onComplete,[t],e)}function ia(t){var e=t.chart,i=e.options.animation;d(i&&i.onProgress,[t],e)}function sa(t){return xe()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t=t&&t.canvas?t.canvas:t}const aa={},na=t=>{const e=sa(t);return Object.values(aa).filter(t=>t.canvas===e).pop()};class i{static defaults=R;static instances=aa;static overrides=fe;static registry=b;static version="4.3.3";static getChart=na;static register(...t){b.add(...t),oa()}static unregister(...t){b.remove(...t),oa()}constructor(t,e){const i=this.config=new Ks(e),s=sa(t),a=na(s);if(a)throw new Error("Canvas is already in use. Chart with ID '"+a.id+"' must be destroyed before the canvas with ID '"+a.canvas.id+"' can be reused.");var e=i.createResolver(i.chartOptionScopes(),this.getContext()),t=(this.platform=new(i.platform||fs(s)),this.platform.updateConfig(i),this.platform.acquireContext(s,e.aspectRatio)),n=t&&t.canvas,o=n&&n.height,r=n&&n.width;this.id=F(),this.ctx=t,this.canvas=n,this.width=r,this.height=o,this._options=e,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Vs,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=Pt(t=>this.update(t),e.resizeDelay||0),this._dataChanges=[],aa[this.id]=this,t&&n?(l.listen(this,"complete",ea),l.listen(this,"progress",ia),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){var{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:s,_aspectRatio:a}=this;return P(t)?e&&a?a:s?i/s:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return b}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():Ce(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Ie(this.canvas,this.ctx),this}stop(){return l.stop(this),this}resize(t,e){l.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){var i=this.options,s=this.canvas,a=i.maintainAspectRatio&&this.aspectRatio,s=this.platform.getMaximumSize(s,t,e,a),t=i.devicePixelRatio||this.platform.getDevicePixelRatio(),e=this.width?"resize":"attach";this.width=s.width,this.height=s.height,this._aspectRatio=this.aspectRatio,Ce(this,t,!0)&&(this.notifyPlugins("resize",{size:s}),d(i.onResize,[this,s],this),this.attached&&this._doResize(e)&&this.render())}ensureScalesHaveIDs(){k(this.options.scales||{},(t,e)=>{t.id=e})}buildOrUpdateScales(){const o=this.options,s=o.scales,r=this.scales,l=Object.keys(r).reduce((t,e)=>(t[e]=!1,t),{});let t=[];k(t=s?t.concat(Object.keys(s).map(t=>{var e=s[t],t=Ns(t,e),i="r"===t,t="x"===t;return{options:e,dposition:i?"chartArea":t?"bottom":"left",dtype:i?"radialLinear":t?"category":"linear"}})):t,t=>{const e=t.options,i=e.id,s=Ns(i,e),a=T(e.type,t.dtype);void 0!==e.position&&Qs(e.position,s)===Qs(t.dposition)||(e.position=t.dposition),l[i]=!0;let n=null;i in r&&r[i].type===a?n=r[i]:(n=new(b.getScale(a))({id:i,type:a,ctx:this.ctx,chart:this}),r[n.id]=n),n.init(e,o)}),k(l,(t,e)=>{t||delete r[e]}),k(r,t=>{a.configure(this,t,t.options),a.addBox(this,t)})}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort((t,e)=>t.index-e.index),ei.length&&delete this._stacks,t.forEach((e,t)=>{0===i.filter(t=>t===e._dataset).length&&this._destroyDatasetMeta(t)})}buildOrUpdateControllers(){const e=[],i=this.data.datasets;let s,a;for(this._removeUnreferencedMetasets(),s=0,a=i.length;s{this.getDatasetMeta(e).controller.reset()},this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const s=this.config,a=(s.update(),this._options=s.createResolver(s.chartOptionScopes(),this.getContext())),n=this._animationsDisabled=!a.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1!==this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0})){const o=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let i=0;for(let t=0,e=this.data.datasets.length;t{t.reset()}),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(ta("z","_idx"));var{_active:t,_lastEvent:e}=this;e?this._eventHandler(e,!0):t.length&&this._updateHoverStyles(t,t,!0),this.render()}}_updateScales(){k(this.scales,t=>{a.removeBox(this,t)}),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){var t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);Z(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){var t,e,i,s,a=this["_hiddenIndices"];for({method:t,start:e,count:i}of this._getUniformDataChanges()||[]){n=void 0;o=void 0;r=void 0;s=void 0;var n=a;var o=e;var r="_removeElements"===t?-i:i;const l=Object.keys(n);for(const h of l){const l=+h;l>=o&&(s=n[h],delete n[h],(0o)&&(n[l+r]=s))}}}_getUniformDataChanges(){const t=this._dataChanges;if(t&&t.length){this._dataChanges=[];var e=this.data.datasets.length,i=e=>new Set(t.filter(t=>t[0]===e).map((t,e)=>e+","+t.splice(1).join(","))),s=i(0);for(let t=1;tt.split(",")).map(t=>({method:t[1],start:+t[2],count:+t[3]}))}}_updateLayout(t){if(!1!==this.notifyPlugins("beforeLayout",{cancelable:!0})){a.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],k(this.boxes,t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))},this),this._layers.forEach((t,e)=>{t._idx=e}),this.notifyPlugins("afterLayout")}}_updateDatasets(i){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:i,cancelable:!0})){for(let t=0,e=this.data.datasets.length;tt&&t._dataset===e).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Pi(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){var e=this.data.datasets[t];if(!e)return!1;t=this.getDatasetMeta(t);return"boolean"==typeof t.hidden?!t.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(e,t,i){const s=i?"show":"hide",a=this.getDatasetMeta(e),n=a.controller._resolveAnimations(void 0,s);G(t)?(a.data[t].hidden=!i,this.update()):(this.setDatasetVisibility(e,i),n.update(a,{visible:i}),this.update(t=>t.datasetIndex===e?s:void 0))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),l.remove(this),t=0,e=this.data.datasets.length;t{s.addEventListener(this,t,e),i[t]=e},a=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};k(this.options.events,t=>e(t,a))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const i=this._responsiveListeners,s=this.platform,t=(t,e)=>{s.addEventListener(this,t,e),i[t]=e},e=(t,e)=>{i[t]&&(s.removeEventListener(this,t,e),delete i[t])},a=(t,e)=>{this.canvas&&this.resize(t,e)};let n;const o=()=>{e("attach",o),this.attached=!0,this.resize(),t("resize",a),t("detach",n)};n=()=>{this.attached=!1,e("resize",a),this._stop(),this._resize(0,0),t("attach",o)},(s.isAttached(this.canvas)?o:n)()}unbindEvents(){k(this._listeners,(t,e)=>{this.platform.removeEventListener(this,e,t)}),this._listeners={},k(this._responsiveListeners,(t,e)=>{this.platform.removeEventListener(this,e,t)}),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){var s=i?"set":"remove";let a,n,o,r;for("dataset"===e&&(a=this.getDatasetMeta(t[0].datasetIndex)).controller["_"+s+"DatasetHoverStyle"](),o=0,r=t.length;o{var i=this.getDatasetMeta(t);if(i)return{datasetIndex:t,element:i.data[e],index:e};throw new Error("No dataset found at index "+t)});W(t,e)||(this._active=t,this._lastEvent=null,this._updateHoverStyles(t,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(e){return 1===this._plugins._cache.filter(t=>t.plugin.id===e).length}_updateHoverStyles(t,e,i){var s=this.options.hover,a=(t,i)=>t.filter(e=>!i.some(t=>e.datasetIndex===t.datasetIndex&&e.index===t.index)),n=a(e,t),i=i?t:a(t,e);n.length&&this.updateHoverStyle(n,s.mode,!1),i.length&&s.mode&&this.updateHoverStyle(i,s.mode,!0)}_eventHandler(e,t){const i={event:e,replay:t,cancelable:!0,inChartArea:this.isPointInArea(e)},s=t=>(t.options.events||this.options.events).includes(e.native.type);if(!1!==this.notifyPlugins("beforeEvent",i,s))return t=this._handleEvent(e,t,i.inChartArea),i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(t||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:a}=this,n=e,o=this._getActiveElements(t,s,i,n),r=J(t),l=(h=t,c=this._lastEvent,i&&"mouseout"!==h.type?r?c:h:null);i&&(this._lastEvent=null,d(a.onHover,[t,o,this],this),r&&d(a.onClick,[t,o,this],this));var h,c=!W(o,s);return(c||e)&&(this._active=o,this._updateHoverStyles(o,s,e)),this._lastEvent=l,c}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;i=this.options.hover;return this.getElementsAtEventForMode(t,i.mode,i,s)}}function oa(){k(i.instances,t=>t._plugins.invalidate())}function ra(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}var la={_date:class Un{static override(t){Object.assign(Un.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return ra()}parse(){return ra()}format(){return ra()}add(){return ra()}diff(){return ra()}startOf(){return ra()}endOf(){return ra()}}};function ha(i,s,a,n){if(O(i)){var o=i,r=s,l=a,h=n,c=l.parse(o[0],h),o=l.parse(o[1],h),h=Math.min(c,o),d=Math.max(c,o);let t=h,e=d;Math.abs(h)>Math.abs(d)&&(t=d,e=h),r[l.axis]=e,r._custom={barStart:t,barEnd:e,start:c,end:o,min:h,max:d}}else s[a.axis]=a.parse(i,n);return s}function ca(t,e,i,s){const a=t.iScale,n=t.vScale,o=a.getLabels(),r=a===n,l=[];let h,c,d,u;for(c=(h=i)+s;h"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(s){const t=s.data;if(t.labels.length&&t.datasets.length){const{pointStyle:a,color:n}=s.legend.options["labels"];return t.labels.map((t,e)=>{var i=s.getDatasetMeta(0).controller.getStyle(e);return{text:t,fillStyle:i.backgroundColor,strokeStyle:i.borderColor,fontColor:n,lineWidth:i.borderWidth,pointStyle:a,hidden:!s.getDataVisibility(e),index:e}})}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(s,a){const n=this.getDataset().data,o=this._cachedMeta;if(!1===this._parsing)o._parsed=n;else{let t,e,i=t=>+n[t];if(A(n[s])){const{key:s="value"}=this._parsing;i=t=>+m(n[t],s)}for(e=(t=s)+a;tpt(t,r,l,!0)?1:Math.max(e,e*s,i,i*s),f=(t,e,i)=>pt(t,r,l,!0)?-1:Math.min(e,e*s,i,i*s),p=g(0,h,d),m=g(D,c,u),b=f(S,h,d),x=f(S+D,c,u);i=(p-b)/2,a=(m-x)/2,n=-(p+b)/2,o=-(m+x)/2}return{ratioX:i,ratioY:a,offsetX:n,offsetY:o}}(c,h,r),p=(i.width-n)/d,m=(i.height-n)/u,b=Math.max(Math.min(p,m)/2,0),x=B(this.options.radius,b),v=(x-Math.max(x*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=g*x,this.offsetY=f*x,s.total=this.calculateTotal(),this.outerRadius=x-v*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-v*l,0),this.updateElements(a,0,a.length,t)}_circumference(t,e){var i=this.options,s=this._cachedMeta,a=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*a/_)}updateElements(t,e,i,s){const a="reset"===s,n=this.chart,o=n.chartArea,r=n.options.animation,l=(o.left+o.right)/2,h=(o.top+o.bottom)/2,c=a&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,{sharedOptions:g,includeOptions:f}=this._getSharedOptions(e,s);let p,m=this._getRotation();for(p=0;p{var i=s.getDatasetMeta(0).controller.getStyle(e);return{text:t,fillStyle:i.backgroundColor,strokeStyle:i.borderColor,fontColor:n,lineWidth:i.borderWidth,pointStyle:a,hidden:!s.getDataVisibility(e),index:e}})}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){var e=this._cachedMeta,i=this.chart,s=i.data.labels||[],e=de(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:e}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){var e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,s={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach((t,e)=>{var i=this.getParsed(e).r;!isNaN(i)&&this.chart.getDataVisibility(e)&&(is.max&&(s.max=i))}),s}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),a=Math.max(s/2,0),n=(a-Math.max(i.cutoutPercentage?a/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=a-n*this.index,this.innerRadius=this.outerRadius-n}updateElements(s,a,t,n){const o="reset"===n,r=this.chart,l=r.options.animation,h=this._cachedMeta.rScale,c=h.xCenter,d=h.yCenter,u=h.getIndexAngle(0)-.5*S;let g,f=u;var p=360/this.countVisibleElements();for(g=0;g{!isNaN(this.getParsed(e).r)&&this.chart.getDataVisibility(e)&&i++}),i}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?L(this.resolveDataElementOptions(t,e).angle||i):0}}var ma=Object.freeze({__proto__:null,BarController:class extends Os{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(t,e,i,s){return ca(t,e,i,s)}parseArrayData(t,e,i,s){return ca(t,e,i,s)}parseObjectData(t,e,i,s){const{iScale:a,vScale:n}=t,{xAxisKey:o="x",yAxisKey:r="y"}=this._parsing,l="x"===a.axis?o:r,h="x"===n.axis?o:r,c=[];let d,u,g,f;for(u=(d=i)+s;dn.x,e="left","right"):(t=n.baset.controller.options.grouped),a=e.options.stacked,n=[];for(const e of s)if((void 0===i||!(t=>{var e=t.controller.getParsed(i),e=e&&e[t.vScale.axis];if(P(e)||isNaN(e))return!0})(e))&&((!1===a||-1===n.indexOf(e.stack)||void 0===a&&void 0===e.stack)&&n.push(e.stack),e.index===t))break;return n.length||n.push(void 0),n}_getStackCount(t){return this._getStacks(void 0,t).length}_getStackIndex(t,e,i){const s=this._getStacks(t,i),a=void 0!==e?s.indexOf(e):-1;return-1===a?s.length-1:a}_getRuler(){const t=this.options,e=this._cachedMeta,i=e.iScale,s=[];let a,n;for(a=0,n=e.data.length;at-e))}return s._cache.$bar}(e,t.type);let s,a,n,o,r=e._length;var l=()=>{32767!==n&&-32768!==n&&(G(o)&&(r=Math.min(r,Math.abs(n-o)||r)),o=n)};for(s=0,a=i.length;s=m?1:-1))*n),u===o&&(x-=d/2);const t=e.getPixelForDecimal(0),P=e.getPixelForDecimal(1),a=Math.min(t,P),l=Math.max(t,P);x=Math.max(Math.min(x,l),a),c=x+d,i&&!h&&(r._stacks[e.axis]._visualValues[s]=e.getValueForPixel(c)-e.getValueForPixel(x))}if(x===e.getPixelForValue(o)){const t=y(d)*e.getLineWidthForValue(o)/2;x+=t,d-=t}return{size:d,base:x,head:c,center:c+d/2}}_calculateBarIndexPixels(t,e){const i=e.scale,s=this.options,a=s.skipNull,n=T(s.maxBarThickness,1/0);let o,r;if(e.grouped){const i=a?this._getStackCount(t):e.stackCount,T=("flex"===s.barThickness?function(t,e,i,s){var a=e.pixels,n=a[t];let o=0=b?x.skip=!0:(y=P((_=this.getParsed(t))[u]),M=x[d]=n.getPixelForValue(_[d],t),w=x[u]=a||y?o.getBasePixel():o.getPixelForValue(r?this.applyStack(o,_,r):_[u],t),x.skip=isNaN(M)||isNaN(w)||y,x.stop=0p,f&&(x.parsed=_,x.raw=l.data[t]),c&&(x.options=h||this.resolveDataElementOptions(t,g.active?"active":s)),m||this.updateElement(g,t,x,s),v=_)}}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;var a=s[0].size(this.resolveDataElementOptions(0)),n=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,a,n)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}},PieController:class extends fa{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:pa,RadarController:class extends Os{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],a=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);var n={_loop:!0,_fullLoop:a.length===s.length,options:e};this.updateElement(i,void 0,n,t)}this.updateElements(s,0,s.length,t)}updateElements(e,i,s,a){const n=this._cachedMeta.rScale,o="reset"===a;for(let t=i;tm,p&&(f.parsed=s,f.raw=h.data[t]),d&&(f.options=c||this.resolveDataElementOptions(t,i.active?"active":a)),b||this.updateElement(i,t,f,a),x=s}this.updateSharedOptions(c,a,t)}getMaxOverflow(){const t=this._cachedMeta,i=t.data||[];if(!this.options.showLine){let e=0;for(let t=i.length-1;0<=t;--t)e=Math.max(e,i[t].size(this.resolveDataElementOptions(t))/2);return 0{var e=(i-Math.min(a,t))*s/2;return C(t,0,Math.min(a,e))};return{outerStart:o(t.outerStart),outerEnd:o(t.outerEnd),innerStart:C(t.innerStart,0,n),innerEnd:C(t.innerEnd,0,n)}}(e,h,d,l-g),b=d-c,x=d-f,v=g+c/b,_=l-f/x,y=h+p,M=h+m,w=g+p/y,k=l-m/M;if(t.beginPath(),n){const e=(v+_)/2;if(t.arc(o,r,d,v,e),t.arc(o,r,d,e,_),0(o+(h?r-t:t))%n,v=()=>{g!==f&&(t.lineTo(m,f),t.lineTo(m,g),t.lineTo(m,p))};for(l&&(d=a[x(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c)if(!(d=a[x(c)]).skip){const e=d.x,i=d.y,s=0|e;s===u?(if&&(f=i),m=(b*m+e)/++b):(v(),t.lineTo(e,i),u=s,b=0,g=f=i),p=i}v()}function ka(t){var e=t.options,i=e.borderDash&&e.borderDash.length;return t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i?Ma:wa}const Sa="function"==typeof Path2D;class Pa extends e{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){var i,s=this.options;!s.tension&&"monotone"!==s.cubicInterpolationMode||s.stepped||this._pointsUpdated||(i=s.spanGaps?this._loop:this._fullLoop,hi(this._points,s,t,i,e),this._pointsUpdated=!0)}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Ri(this,this.options.segment))}first(){var t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){var t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(i,s){var a=this.options,n=i[s],o=this.points,r=Ei(this,{property:s,start:n,end:n});if(r.length){const l=[],h=a.stepped?pi:a.tension||"monotone"===a.cubicInterpolationMode?mi:fi;let e,t;for(e=0,t=r.length;e"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){var{angle:t,distance:e}=ut(this.getProps(["x","y"],i),{x:t,y:e}),{startAngle:i,endAngle:s,innerRadius:a,outerRadius:n,circumference:o}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),r=(this.options.spacing+this.options.borderWidth)/2,o=T(o,s-i)>=_||pt(t,i,s),t=c(e,a+r,n+r);return o&&t}getCenterPoint(t){var{x:t,y:e,startAngle:i,endAngle:s,innerRadius:a,outerRadius:n}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:o,spacing:r}=this.options,i=(i+s)/2,s=(a+n+r+o)/2;return{x:t+Math.cos(i)*s,y:e+Math.sin(i)*s}}tooltipPosition(t){return this.getCenterPoint(t)}draw(e){var{options:i,circumference:s}=this,a=(i.offset||0)/4,n=(i.spacing||0)/2,o=i.circular;if(this.pixelMargin="inner"===i.borderAlign?.33:0,this.fullCircles=s>_?Math.floor(s/_):0,!(0===s||this.innerRadius<0||this.outerRadius<0)){e.save();var r=(this.startAngle+this.endAngle)/2,r=(e.translate(Math.cos(r)*a,Math.sin(r)*a),a*(1-Math.sin(Math.min(S,s||0))));e.fillStyle=i.backgroundColor,e.strokeStyle=i.borderColor;{var l=e;a=this;s=r;i=n;var h=o;var{fullCircles:c,startAngle:d,circumference:u}=a;let t=a.endAngle;if(c){xa(l,a,s,i,t,h);for(let t=0;ts=e?s:t,r=t=>a=i?a:t;if(t){const t=y(s),e=y(a);t<0&&e<0?r(0):0g&&(k=nt(w*k/g/u)*u),P(r)||(_=Math.pow(10,r),k=Math.ceil(k*_)/_),M="ticks"===s?(y=Math.floor(f/k)*k,Math.ceil(p/k)*k):(y=f,p),m&&b&&a&<((o-n)/a,k/1e3)?(w=Math.round(Math.min((o-n)/k,h)),k=(o-n)/w,y=n,M=o):x?(y=m?n:y,M=b?o:M,w=l-1,k=(M-y)/w):w=at(w=(M-y)/k,Math.round(w),k/1e3)?Math.round(w):Math.ceil(w);e=Math.max(dt(k),dt(y));_=Math.pow(10,P(r)?e:r),y=Math.round(y*_)/_,M=Math.round(M*_)/_;let S=0;for(m&&(d&&y!==n?(i.push({value:n}),yo)break;i.push({value:t})}return b&&d&&M!==o?i.length&&at(i[i.length-1].value,o,Ia(o,v,t))?i[i.length-1].value=o:i.push({value:o}):b&&M!==o||i.push({value:M}),i}({maxTicks:Math.max(2,i),bounds:t.bounds,min:t.min,max:t.max,precision:e.precision,step:e.stepSize,count:e.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:e.minRotation||0,includeBounds:!1!==e.includeBounds},this._range||this);return"ticks"===t.bounds&&ht(s,this,"value"),t.reverse?(s.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),s}configure(){var t=this.ticks;let e=this.min,i=this.max;super.configure(),this.options.offset&&t.length&&(t=(i-e)/Math.max(t.length-1,1)/2,e-=t,i+=t),this._startValue=e,this._endValue=i,this._valueRange=i-e}getLabelForValue(t){return de(t,this.chart.options.locale,this.options.ticks.format)}}class Fa extends za{static id="linear";static defaults={ticks:{callback:ge.formatters.numeric}};determineDataLimits(){var{min:t,max:e}=this.getMinMax(!0);this.min=p(t)?t:0,this.max=p(e)?e:1,this.handleTickRangeOptions()}computeTickLimit(){var t=this.isHorizontal(),e=t?this.width:this.height,i=L(this.options.ticks.minRotation),t=(t?Math.sin(i):Math.cos(i))||.001,i=this._resolveTickFontOptions(0);return Math.ceil(e/Math.min(40,i.lineHeight/t))}getPixelForValue(t){return null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const Va=t=>Math.floor(r(t)),Ba=(t,e)=>Math.pow(10,Va(t)+e);function Wa(t){return 1==t/Math.pow(10,Va(t))}function Na(t,e,i){i=Math.pow(10,i),t=Math.floor(t/i);return Math.ceil(e/i)-t}class Ha extends zs{static id="logarithmic";static defaults={ticks:{callback:ge.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,e){t=za.prototype.parse.apply(this,[t,e]);if(0!==t)return p(t)&&0s=e?s:t,n=t=>a=i?a:t;s===a&&(s<=0?(t(1),n(10)):(t(Ba(s,-1)),n(Ba(a,1)))),s<=0&&t(Ba(a,-1)),a<=0&&n(Ba(s,1)),this.min=s,this.max=a}buildTicks(){const t=this.options,e=function(t,{min:e,max:i}){e=g(t.min,e);const s=[],a=Va(e);let n=function(t,e){let i=Va(e-t);for(;10n?Math.pow(10,a):0,h=Math.round((e-l)*o)/o,c=Math.floor((e-l)/r/10)*r*10;let d=Math.floor((h-c)/Math.pow(10,n)),u=g(t.min,Math.round((l+c+d*Math.pow(10,n))*o)/o);for(;uf.r&&(t=(m.end-f.r)/x,g.r=Math.max(g.r,f.r+t)),b.startf.b&&(e=(b.end-f.b)/p,g.b=Math.max(g.b,f.b+e))}}var d,u;e.setCenterPoint(i.l-s.l,s.r-i.r,i.t-s.t,s.b-i.b),e._pointLabelItems=function(e,i,s){const a=[],n=e._pointLabels.length,t=e.options,{centerPointLabels:o,display:r}=t.pointLabels,l={extra:ja(t)/2,additionalAngle:o?S/n:0};let h;for(let t=0;tt,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(t){super(t),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){var t=this._padding=I(ja(this.options)/2),e=this.width=this.maxWidth-t.width,i=this.height=this.maxHeight-t.height;this.xCenter=Math.floor(this.left+e/2+t.left),this.yCenter=Math.floor(this.top+i/2+t.top),this.drawingArea=Math.floor(Math.min(e,i)/2)}determineDataLimits(){var{min:t,max:e}=this.getMinMax(!1);this.min=p(t)&&!isNaN(t)?t:0,this.max=p(e)&&!isNaN(e)?e:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/ja(this.options))}generateTickLabels(t){za.prototype.generateTickLabels.call(this,t),this._pointLabels=this.getLabels().map((t,e)=>{t=d(this.options.pointLabels.callback,[t,e],this);return t||0===t?t:""}).filter((t,e)=>this.chart.getDataVisibility(e))}fit(){var t=this.options;t.display&&t.pointLabels.display?$a(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return v(t*(_/(this._pointLabels.length||1))+L(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if(P(t))return NaN;var e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(P(t))return NaN;t/=this.drawingArea/(this.max-this.min);return this.options.reverse?this.max-t:this.min+t}getPointLabelContext(t){var e=this._pointLabels||[];if(0<=t&&t0!==t)?(g.beginPath(),je(g,{x:f,y:r,w:x,h:m,radius:p}),g.fill()):g.fillRect(f,r,x,m)}var p=z(l.font),{x:v,y:b,textAlign:g}=o;He(_,n._pointLabels[t],v,b+p.lineHeight/2,p,{color:l.color,textAlign:g,textBaseline:"middle"})}}}if(h.display&&this.ticks.forEach((t,e)=>{if(0!==e){u=this.getDistanceFromCenterForValue(t.value);t=this.getContext(e),e=h.setContext(t),t=c.setContext(t);{var i=this,s=u,a=d;const n=i.ctx,o=e.circular,{color:r,lineWidth:l}=e;!o&&!a||!r||!l||s<0||(n.save(),n.strokeStyle=r,n.lineWidth=l,n.setLineDash(t.dash),n.lineDashOffset=t.dashOffset,n.beginPath(),Ua(i,s,o,a),n.closePath(),n.stroke(),n.restore())}}}),i.display){for(t.save(),s=d-1;0<=s;s--){const h=i.setContext(this.getPointLabelContext(s)),{color:c,lineWidth:d}=h;d&&c&&(t.lineWidth=d,t.strokeStyle=c,t.setLineDash(h.borderDash),t.lineDashOffset=h.borderDashOffset,u=this.getDistanceFromCenterForValue(e.ticks.reverse?this.min:this.max),a=this.getPointPosition(s,u),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(a.x,a.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const o=this.ctx,r=this.options,l=r.ticks;if(l.display){var t=this.getIndexAngle(0);let a,n;o.save(),o.translate(this.xCenter,this.yCenter),o.rotate(t),o.textAlign="center",o.textBaseline="middle",this.ticks.forEach((t,e)=>{if(0!==e||r.reverse){var i=l.setContext(this.getContext(e)),s=z(i.font);if(a=this.getDistanceFromCenterForValue(this.ticks[e].value),i.showLabelBackdrop){o.font=s.string,n=o.measureText(t.label).width,o.fillStyle=i.backdropColor;const r=I(i.backdropPadding);o.fillRect(-n/2-r.left,-a-s.size/2-r.top,n+r.width,s.size+r.height)}He(o,t.label,0,-a,s,{color:i.color,strokeColor:i.textStrokeColor,strokeWidth:i.textStrokeWidth})}}),o.restore()}}drawTitle(){}}const qa={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},h=Object.keys(qa);function Ka(t,e){return t-e}function Ga(t,e){if(P(e))return null;const i=t._adapter,{parser:s,round:a,isoWeekday:n}=t._parseOpts;let o=e;return null===(o=p(o="function"==typeof s?s(o):o)?o:"string"==typeof s?i.parse(o,s):i.parse(o))?null:+(o=a?"week"!==a||!rt(n)&&!0!==n?i.startOf(o,a):i.startOf(o,"isoWeek",n):o)}function Za(e,i,s,a){const n=h.length;for(let t=h.indexOf(e);t=e?i[s]:i[a]]=!0):t[e]=!0}function Qa(i,t,s){const a=[],n={},e=t.length;let o,r;for(o=0;o=h.indexOf(s);t--){const s=h[t];if(qa[s].common&&e._adapter.diff(n,a,s)>=i-1)return s}return h[s?h.indexOf(s):0]}(this,n.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(i){for(let t=h.indexOf(i)+1,e=h.length;t+t.value))}initOffsets(t=[]){let e,i,s=0,a=0;this.options.offset&&t.length&&(e=this.getDecimalForValue(t[0]),s=1===t.length?1-e:(this.getDecimalForValue(t[1])-e)/2,i=this.getDecimalForValue(t[t.length-1]),a=1===t.length?i:(i-this.getDecimalForValue(t[t.length-2]))/2);t=t.length<3?.5:.25;s=C(s,0,t),a=C(a,0,t),this._offsets={start:s,end:a,factor:1/(s+1+a)}}_generate(){const t=this._adapter,e=this.min,i=this.max,s=this.options,a=s.time,n=a.unit||Za(a.minUnit,e,i,this._getLabelCapacity(e)),o=T(s.ticks.stepSize,1),r="week"===n&&a.isoWeekday,l=rt(r)||!0===r,h={};let c,d,u=e;if(l&&(u=+t.startOf(u,"isoWeek",r)),u=+t.startOf(u,l?"day":n),t.diff(i,e,n)>1e5*o)throw new Error(e+" and "+i+" are too far apart with stepSize of "+o+" "+n);var g="data"===s.ticks.source&&this.getDataTimestamps();for(c=u,d=0;c+t)}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){var i=this.options.time.displayFormats,s=this._unit,e=e||i[s];return this._adapter.format(t,e)}_tickFormatFunction(t,e,i,s){var a=this.options,n=a.ticks.callback;if(n)return d(n,[t,e,i],this);var n=a.time.displayFormats,a=this._unit,o=this._majorUnit,a=a&&n[a],n=o&&n[o],i=i[e],e=o&&n&&i&&i.major;return this._adapter.format(t,s||(e?n:a))}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=f(t,"pos",e)),{pos:s,time:n}=t[r],{pos:a,time:o}=t[l]):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=f(t,"time",e)),{time:s,pos:n}=t[r],{time:a,pos:o}=t[l]);i=a-s;return i?n+(o-n)*(e-s)/i:n}var sn=Object.freeze({__proto__:null,CategoryScale:class extends zs{static id="category";static defaults={ticks:{callback:Ra}};constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){var e=this._addedLabels;if(e.length){const t=this.getLabels();for(var{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if(P(t))return null;var i,s,a,n,o,r,l=this.getLabels();return a=e=isFinite(e)&&l[e]===t?e:(i=l,s=T(e,t=t),a=this._addedLabels,-1===(r=i.indexOf(t))?(o=s,a=a,"string"==typeof(n=t)?(o=i.push(n)-1,a.unshift({index:o,label:n})):isNaN(n)&&(o=null),o):r!==i.lastIndexOf(t)?s:r),n=l.length-1,null===a?null:C(Math.round(a),0,n)}determineDataLimits(){var{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const e=this.min,i=this.max,t=this.options.offset,s=[];let a=this.getLabels();a=0===e&&i===a.length-1?a:a.slice(e,i+1),this._valueRange=Math.max(a.length-(t?0:1),1),this._startValue=this.min-(t?.5:0);for(let t=e;t<=i;t++)s.push({value:t});return s}getLabelForValue(t){return Ra.call(this,t)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(t){return null===(t="number"!=typeof t?this.parse(t):t)?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getPixelForTick(t){var e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:Fa,LogarithmicScale:Ha,RadialLinearScale:Xa,TimeScale:tn,TimeSeriesScale:class extends tn{static id="timeseries";static defaults=tn.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){var t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=en(e,this.min),this._tableRange=en(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],a=[];let n,o,r,l,h;for(n=0,o=t.length;n=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(n=0,o=s.length;nt-e)}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const e=this.getDataTimestamps(),i=this.getLabelTimestamps();return t=e.length&&i.length?this.normalize(e.concat(i)):e.length?e:i,t=this._cache.all=t}getDecimalForValue(t){return(en(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){var e=this._offsets,t=this.getDecimalForPixel(t)/e.factor-e.end;return en(this._table,t*this._tableRange+this._minPos,!0)}}});const an=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],nn=an.map(t=>t.replace("rgb(","rgba(").replace(")",", 0.5)"));function on(t){return an[t%an.length]}function rn(t){return nn[t%nn.length]}function ln(n){let o=0;return(t,e)=>{var i,s,a,e=n.getDatasetMeta(e).controller;e instanceof fa?o=(s=t,a=o,s.backgroundColor=s.data.map(()=>on(a++)),a):e instanceof pa?o=(s=t,i=o,s.backgroundColor=s.data.map(()=>rn(i++)),i):e&&(o=(e=t,t=o,e.borderColor=on(t),e.backgroundColor=rn(t),++t))}}function hn(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return 1}var cn={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(i.enabled){const{data:{datasets:s},options:a}=t.config,n=a["elements"];!i.forceOverride&&(hn(s)||a&&(a.borderColor||a.backgroundColor)||n&&hn(n))||(i=ln(t),s.forEach(i))}}};function dn(t){var e;t._decimated&&(e=t._data,delete t._decimated,delete t._data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,writable:!0,value:e}))}function un(t){t.data.datasets.forEach(t=>{dn(t)})}var gn={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(r,t,M)=>{if(M.enabled){const l=r.width;r.data.datasets.forEach((e,t)=>{var{_data:i,indexAxis:s}=e,h=r.getDatasetMeta(t),a=i||e.data;if("y"!==ki([s,r.options.indexAxis])&&h.controller.supportsDecimation){t=r.scales[h.xAxisID];if(("linear"===t.type||"time"===t.type)&&!r.options.parsing){var{start:n,count:o}=function(t){var e=t.length;let i,s=0;const a=h["iScale"],{min:n,max:o,minDefined:r,maxDefined:l}=a.getUserBounds();return r&&(s=C(f(t,a.axis,n).lo,0,e-1)),i=l?C(f(t,a.axis,o).hi+1,s,e)-s:e-s,{start:s,count:i}}(a);if(o<=(M.threshold||4*l))dn(e);else{let t;switch(P(i)&&(e._data=a,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),M.algorithm){case"lttb":t=function(s,a,n,t){var e=M.samples||t;if(n<=e)return s.slice(a,a+n);const o=[],r=(n-2)/(e-2);let l=0;const h=a+n-1;let c,d,u,g,f,p=a;for(o[l++]=s[p],c=0;cu&&(u=g,d=s[t],f=t);o[l++]=d,p=f}return o[l++]=s[h],o}(a,n,o,l);break;case"min-max":t=function(t,e,i,s){let a,n,o,r,l,h,c,d,u,g,f=0,p=0;const m=[],b=e+i-1,x=t[e].x,v=t[b].x-x;for(a=e;ag&&(g=r,c=a),f=(p*f+n.x)/++p;else{const i=a-1;if(!P(h)&&!P(c)){const e=Math.min(h,c),P=Math.max(h,c);e!==d&&e!==i&&m.push({...t[e],x:f}),P!==d&&P!==i&&m.push({...t[P],x:f})}0{e=pn(t,e,a);t=a[t],e=a[e];null!==s?(n.push({x:t.x,y:s}),n.push({x:e.x,y:s})):null!==i&&(n.push({x:i,y:t.y}),n.push({x:i,y:e.y}))}),n}(t)).length?new Pa({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function xn(t){return t&&!1!==t.fill}function vn(e,i,s){const a=[];for(let t=0;t{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=t.pointStyleWidth||Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class Cn extends e{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const i=this.options.labels||{};let t=d(i.generateLabels,[this.chart],this)||[];i.filter&&(t=t.filter(t=>i.filter(t,this.chart.data))),i.sort&&(t=t.sort((t,e)=>i.sort(t,e,this.chart.data))),this.options.reverse&&t.reverse(),this.legendItems=t}fit(){const{options:i,ctx:s}=this;if(i.display){var a=i.labels,n=z(a.font),o=n.size,r=this._computeTitleHeight(),{boxWidth:a,itemHeight:l}=Dn(a,o);let t,e;s.font=n.string,this.isHorizontal()?(t=this.maxWidth,e=this._fitRows(r,o,a,l)+10):(e=this.maxHeight,t=this._fitCols(r,n,a,l)+10),this.width=Math.min(t,i.maxWidth||this.maxWidth),this.height=Math.min(e,i.maxHeight||this.maxHeight)}else this.width=this.height=0}_fitRows(t,i,s,a){const{ctx:n,maxWidth:o,options:{labels:{padding:r}}}=this,l=this.legendHitBoxes=[],h=this.lineWidths=[0],c=a+r;let d=t,u=(n.textAlign="left",n.textBaseline="middle",-1),g=-c;return this.legendItems.forEach((t,e)=>{t=s+i/2+n.measureText(t.text).width;(0===e||h[h.length-1]+t+2*r>o)&&(d+=c,h[h.length-(0{o=l,i=r,s=c,a=t,n=h;var i,s,a,n,{itemWidth:t,itemHeight:o}={itemWidth:function(t,e,i){let s=a.text;return s&&"string"!=typeof s&&(s=s.reduce((t,e)=>t.length>e.length?t:e)),t+e.size/2+i.measureText(s).width}(o,i,s),itemHeight:function(t){let e=n;return e="string"!=typeof a.text?On(a,t):e}(i.lineHeight)};0f&&(p+=m+d,g.push({width:m,height:b}),x+=m+d,v++,m=b=0),u[e]={left:x,top:b,col:v,width:t,height:o},m=Math.max(m,t),b+=o+d}),p+=m,g.push({width:m,height:b}),p}adjustHitBoxes(){if(this.options.display){const i=this._computeTitleHeight(),{legendHitBoxes:s,options:{align:a,labels:{padding:n},rtl:t}}=this,o=Di(t,this.left,this.width);if(this.isHorizontal()){let t=0,e=E(a,this.left+n,this.right-this.lineWidths[t]);for(const r of s)t!==r.row&&(t=r.row,e=E(a,this.left+n,this.right-this.lineWidths[t])),r.top+=this.top+i+n,r.left=o.leftForLtr(o.x(e),r.width),e+=r.width+n}else{let t=0,e=E(a,this.top+i+n,this.bottom-this.columnSizes[t].height);for(const l of s)l.col!==t&&(t=l.col,e=E(a,this.top+i+n,this.bottom-this.columnSizes[t].height)),l.top=e,l.left+=this.left+n,l.left=o.leftForLtr(o.x(l.left),l.width),e+=l.height+n}}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){var t;this.options.display&&(Ve(t=this.ctx,this),this._draw(),Be(t))}_draw(){const{options:h,columnSizes:c,lineWidths:d,ctx:u}=this,{align:g,labels:f}=h,p=R.color,m=Di(h.rtl,this.left,this.width),b=z(f.font),x=f["padding"],v=b.size,_=v/2;let y;this.drawTitle(),u.textAlign=m.textAlign("left"),u.textBaseline="middle",u.lineWidth=.5,u.font=b.string;const{boxWidth:M,boxHeight:w,itemHeight:k}=Dn(f,v),S=this.isHorizontal(),P=this._computeTitleHeight(),D=(y=S?{x:E(g,this.left+x,this.right-d[0]),y:this.top+x+P,line:0}:{x:this.left+x,y:E(g,this.top+P+x,this.bottom-c[0].height),line:0},Ci(this.ctx,h.textDirection),k+x);this.legendItems.forEach((t,e)=>{u.strokeStyle=t.fontColor,u.fillStyle=t.fontColor;var i=u.measureText(t.text).width,s=m.textAlign(t.textAlign||(t.textAlign=f.textAlign)),i=M+_+i;let a=y.x,n=y.y;m.setWidth(this.width),S?0this.right&&(n=y.y+=D,y.line++,a=y.x=E(g,this.left+x,this.right-d[y.line])):0this.bottom&&(a=y.x=a+c[y.line].width+x,y.line++,n=y.y=E(g,this.top+P+x,this.bottom-c[y.line].height));var e=m.x(a),o=n,r=t;if(!(isNaN(M)||M<=0||isNaN(w)||w<0)){u.save();var l=T(r.lineWidth,1);if(u.fillStyle=T(r.fillStyle,p),u.lineCap=T(r.lineCap,"butt"),u.lineDashOffset=T(r.lineDashOffset,0),u.lineJoin=T(r.lineJoin,"miter"),u.lineWidth=l,u.strokeStyle=T(r.strokeStyle,p),u.setLineDash(T(r.lineDash,[])),f.usePointStyle){const p={radius:w*Math.SQRT2/2,pointStyle:r.pointStyle,rotation:r.rotation,borderWidth:l},T=m.xPlus(e,M/2);Fe(u,p,T,o+_,f.pointStyleWidth&&M)}else{const f=o+Math.max((v-w)/2,0),p=m.leftForLtr(e,M),T=wi(r.borderRadius);u.beginPath(),Object.values(T).some(t=>0!==t)?je(u,{x:p,y:f,w:M,h:w,radius:T}):u.rect(p,f,M,w),u.fill(),0!==l&&u.stroke()}u.restore()}if(a=Ct(s,a+M+_,S?a+i:this.right,h.rtl),o=m.x(a),e=n,r=t,He(u,r.text,o,e+k/2,b,{strikethrough:r.hidden,textAlign:m.textAlign(r.textAlign)}),S)y.x+=i+x;else if("string"!=typeof t.text){const h=b.lineHeight;y.y+=On(t,h)+x}else y.y+=D}),Oi(this.ctx,h.textDirection)}drawTitle(){const s=this.options,a=s.title,n=z(a.font),o=I(a.padding);if(a.display){const l=Di(s.rtl,this.left,this.width),h=this.ctx,c=a.position,d=n.size/2,u=o.top+d;let t,e=this.left,i=this.width;if(this.isHorizontal())i=Math.max(...this.lineWidths),t=this.top+u,e=E(s.align,e,this.right-i);else{const a=this.columnSizes.reduce((t,e)=>Math.max(t,e.height),0);t=u+E(s.align,this.top,this.bottom-a-s.labels.padding-this._computeTitleHeight())}var r=E(c,e,e+i);h.textAlign=l.textAlign(Dt(c)),h.textBaseline="middle",h.strokeStyle=a.color,h.fillStyle=a.color,h.font=n.string,He(h,a.text,r,t,n)}}_computeTitleHeight(){var t=this.options.title,e=z(t.font),i=I(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,a;if(c(t,this.left,this.right)&&c(e,this.top,this.bottom))for(a=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const s=t.data.datasets,{usePointStyle:a,pointStyle:n,textAlign:o,color:r,useBorderRadius:l,borderRadius:h}=t.legend.options["labels"];return t._getSortedDatasetMetas().map(t=>{var e=t.controller.getStyle(a?0:void 0),i=I(e.borderWidth);return{text:s[t.index].label,fillStyle:e.backgroundColor,fontColor:r,hidden:!t.visible,lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:(i.width+i.height)/4,strokeStyle:e.borderColor,pointStyle:n||e.pointStyle,rotation:e.rotation,textAlign:o||e.textAlign,borderRadius:l&&(h||e.borderRadius),datasetIndex:t.index}},this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class Tn extends e{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){var i=this.options;this.left=0,this.top=0,i.display?(this.width=this.right=t,this.height=this.bottom=e,t=O(i.text)?i.text.length:1,this._padding=I(i.padding),e=t*z(i.font).lineHeight+this._padding.height,this.isHorizontal()?this.height=e:this.width=e):this.width=this.height=this.right=this.bottom=0}isHorizontal(){var t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){var{top:e,left:i,bottom:s,right:a,options:n}=this,o=n.align;let r,l,h,c=0;return r=this.isHorizontal()?(l=E(o,i,a),h=e+t,a-i):(c="left"===n.position?(l=i+t,h=E(o,s,e),-.5*S):(l=a-t,h=E(o,e,s),.5*S),s-e),{titleX:l,titleY:h,maxWidth:r,rotation:c}}draw(){var t,e,i,s,a,n=this.ctx,o=this.options;o.display&&(e=(t=z(o.font)).lineHeight/2+this._padding.top,{titleX:e,titleY:i,maxWidth:s,rotation:a}=this._drawArgs(e),He(n,o.text,0,0,t,{color:o.color,maxWidth:s,rotation:a,textAlign:Dt(o.align),textBaseline:"middle",translation:[e,i]}))}}var Ln={id:"title",_element:Tn,start(t,e,i){var s;t=t,i=i,s=new Tn({ctx:t.ctx,options:i,chart:t}),a.configure(t,s,i),a.addBox(t,s),t.titleBlock=s},stop(t){var e=t.titleBlock;a.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;a.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const En=new WeakMap;var Rn={id:"subtitle",start(t,e,i){var s=new Tn({ctx:t.ctx,options:i,chart:t});a.configure(t,s,i),a.addBox(t,s),En.set(t,s)},stop(t){a.removeBox(t,En.get(t)),En.delete(t)},beforeUpdate(t,e,i){const s=En.get(t);a.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const In={average(t){if(!t.length)return!1;let e,i,s=0,a=0,n=0;for(e=0,i=t.length;et+e.before.length+e.lines.length+e.after.length,0),x=(b+=t.beforeBody.length+t.afterBody.length,d&&(p+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),b&&(p+=g*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(b-g)*l.lineHeight+(b-1)*e.bodySpacing),u&&(p+=e.footerMarginTop+u*c.lineHeight+(u-1)*e.footerSpacing),0);function v(t){m=Math.max(m,i.measureText(t).width+x)}return i.save(),i.font=h.string,k(t.title,v),i.font=l.string,k(t.beforeBody.concat(t.afterBody),v),x=e.displayColors?o+2+e.boxPadding:0,k(s,t=>{k(t.before,v),k(t.lines,v),k(t.after,v)}),x=0,i.font=c.string,k(t.footer,v),i.restore(),{width:m+=f.width,height:p}}function Vn(i,t,s){var e=s.yAlign||t.yAlign||function(){var{y:t,height:e}=s;return ti.height-e/2?"bottom":"center"}();return{xAlign:s.xAlign||t.xAlign||function(a,n,o,t){var{x:e,width:i}=o,{width:s,chartArea:{left:r,right:l}}=a;let h="center";return"center"===t?h=e<=(r+l)/2?"left":"right":e<=i/2?h="left":s-i/2<=e&&(h="right"),h=function(t){var{x:e,width:i}=o,s=n.caretSize+n.caretPadding;return"left"===t&&e+i+s>a.width||"right"===t&&e-i-s<0}(h)?"center":h}(i,t,s,e),yAlign:e}}function Bn(t,i,e,s){var{caretSize:t,caretPadding:a,cornerRadius:n}=t,{xAlign:o,yAlign:r}=e,l=t+a,{topLeft:e,topRight:a,bottomLeft:n,bottomRight:h}=wi(n);let c=function(){let{x:t,width:e}=i;return"right"===o?t-=e:"center"===o&&(t-=e/2),t}();var d=function(){let{y:t,height:e}=i;return"top"===r?t+=l:t-="bottom"===r?e+l:e/2,t}();return"center"===r?"left"===o?c+=l:"right"===o&&(c-=l):"left"===o?c-=Math.max(e,n)+t:"right"===o&&(c+=Math.max(a,h)+t),{x:C(c,0,s.width-i.width),y:C(d,0,s.height-i.height)}}function Wn(t,e,i){i=I(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-i.right:t.x+i.left}function Nn(t){return x([],zn(t))}function Hn(t,e){e=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return e?t.override(e):t}const jn={beforeTitle:t,title(t){if(0{var e={before:[],lines:[],after:[]},i=Hn(s,t);x(e.before,zn(w(i,"beforeLabel",this,t))),x(e.lines,w(i,"label",this,t)),x(e.after,zn(w(i,"afterLabel",this,t))),a.push(e)}),a}getAfterBody(t,e){return Nn(w(e.callbacks,"afterBody",this,t))}getFooter(t,e){var e=e["callbacks"],i=w(e,"beforeFooter",this,t),s=w(e,"footer",this,t),e=w(e,"afterFooter",this,t),t=x([],zn(i));return t=x(t,zn(s)),x(t,zn(e))}_createItems(s){const t=this._active,a=this.chart.data,i=[],n=[],o=[];let e,r,l=[];for(e=0,r=t.length;es.filter(t,e,i,a))),k(l=s.itemSort?l.sort((t,e)=>s.itemSort(t,e,a)):l,t=>{var e=Hn(s.callbacks,t);i.push(w(e,"labelColor",this,t)),n.push(w(e,"labelPointStyle",this,t)),o.push(w(e,"labelTextColor",this,t))}),this.labelColors=i,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let a,n=[];if(s.length){const t=In[i.position].call(this,s,this._eventPosition),e=(n=this._createItems(i),this.title=this.getTitle(n,i),this.beforeBody=this.getBeforeBody(n,i),this.body=this.getBody(n,i),this.afterBody=this.getAfterBody(n,i),this.footer=this.getFooter(n,i),this._size=Fn(this,i)),o=Object.assign({},t,e),r=Vn(this.chart,i,o),l=Bn(i,o,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,a={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(a={opacity:0});this._tooltipItems=n,this.$context=void 0,a&&this._resolveAnimations().update(this,a),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){t=this.getCaretPosition(t,i,s);e.lineTo(t.x1,t.y1),e.lineTo(t.x2,t.y2),e.lineTo(t.x3,t.y3)}getCaretPosition(t,e,i){var{xAlign:s,yAlign:a}=this,{caretSize:i,cornerRadius:n}=i,{topLeft:n,topRight:o,bottomLeft:r,bottomRight:l}=wi(n),{x:t,y:h}=t,{width:e,height:c}=e;let d,u,g,f,p,m;return"center"===a?(p=h+c/2,m="left"===s?(d=t,u=d-i,f=p+i,p-i):(d=t+e,u=d+i,f=p-i,p+i),g=d):(u="left"===s?t+Math.max(n,r)+i:"right"===s?t+e-Math.max(o,l)-i:this.caretX,g="top"===a?(f=h,p=f-i,d=u-i,u+i):(f=h+c,p=f+i,d=u+i,u-i),m=f),{x1:d,x2:u,x3:g,y1:f,y2:p,y3:m}}drawTitle(t,e,i){var s=this.title,a=s.length;let n,o,r;if(a){const l=Di(i.rtl,this.x,this.width);for(t.x=Wn(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",n=z(i.titleFont),o=i.titleSpacing,e.fillStyle=i.titleColor,e.font=n.string,r=0;r0!==t)?(t.beginPath(),t.fillStyle=a.multiKeyBackground,je(t,{x:e,y:g,w:l,h:r,radius:o}),t.fill(),t.stroke(),t.fillStyle=n.backgroundColor,t.beginPath(),je(t,{x:i,y:g+1,w:l-2,h:r-2,radius:o}),t.fill()):(t.fillStyle=a.multiKeyBackground,t.fillRect(e,g,l,r),t.strokeRect(e,g,l,r),t.fillStyle=n.backgroundColor,t.fillRect(i,g+1,l-2,r-2))}t.fillStyle=this.labelTextColors[i]}drawBody(e,i,t){const s=this["body"],{bodySpacing:a,bodyAlign:n,displayColors:o,boxHeight:r,boxWidth:l,boxPadding:h}=t,c=z(t.bodyFont);let d=c.lineHeight,u=0;function g(t){i.fillText(t,f.x(e.x+u),e.y+d/2),e.y+=d+a}const f=Di(t.rtl,this.x,this.width),p=f.textAlign(n);let m,b,x,v,_,y,M;for(i.textAlign=n,i.textBaseline="middle",i.font=c.string,e.x=Wn(this,p,t),i.fillStyle=t.bodyColor,k(this.beforeBody,g),u=o&&"right"!==p?"center"===n?l/2+h:l+2+h:0,v=0,y=s.length;v{var i=this.chart.getDatasetMeta(t);if(i)return{datasetIndex:t,element:i.data[e],index:e};throw new Error("Cannot find a dataset at index "+t)}),i=!W(i,t),s=this._positionChanged(t,e);(i||s)&&(this._active=t,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;var s=this.options,a=this._active||[],i=this._getActiveElements(t,a,e,i),n=this._positionChanged(i,t),a=e||!W(i,a)||n;return a&&(this._active=i,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),a}_getActiveElements(t,e,i,s){var a=this.options;if("mouseout"===t.type)return[];if(!s)return e;const n=this.chart.getElementsAtEventForMode(t,a.mode,a,i);return a.reverse&&n.reverse(),n}_positionChanged(t,e){var{caretX:i,caretY:s,options:a}=this,a=In[a.position].call(this,t,e);return!1!==a&&(i!==a.x||s!==a.y)}}var $n={id:"tooltip",_element:Yn,positioners:In,afterInit(t,e,i){i&&(t.tooltip=new Yn({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;var i;e&&e._willRender()&&(!(i={tooltip:e})!==t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0})&&(e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)))},afterEvent(t,e){var i;t.tooltip&&(i=e.replay,t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0))},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:jn},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return i.register(ma,sn,Ea,s),i.helpers={...Fi},i._adapters=la,i.Animation=bs,i.Animations=xs,i.animator=l,i.controllers=b.controllers.items,i.DatasetController=Os,i.Element=e,i.elements=Ea,i.Interaction=Hi,i.layouts=a,i.platforms=Oe,i.Scale=zs,i.Ticks=ge,Object.assign(i,ma,sn,Ea,s,Oe),i.Chart=i,"undefined"!=typeof window&&(window.Chart=i),i}); \ No newline at end of file diff --git a/public/scripts/charts.js b/public/scripts/charts.js index f6083159..9677a79b 100644 --- a/public/scripts/charts.js +++ b/public/scripts/charts.js @@ -1,18923 +1,14 @@ /*! - * Chart.js - * http://chartjs.org/ - * Version: 2.7.2 - * - * Copyright 2018 Chart.js Contributors - * Released under the MIT license - * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md + * Chart.js v4.3.3 + * https://www.chartjs.org + * (c) 2023 Chart.js Contributors + * Released under the MIT License */ -(function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.Chart = f() } })(function () { - var define, module, exports; return (function () { function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = "MODULE_NOT_FOUND", f } var l = n[o] = { exports: {} }; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++)s(r[o]); return s } return e })()({ - 1: [function (require, module, exports) { - /* MIT license */ - var colorNames = require(5); - - module.exports = { - getRgba: getRgba, - getHsla: getHsla, - getRgb: getRgb, - getHsl: getHsl, - getHwb: getHwb, - getAlpha: getAlpha, - - hexString: hexString, - rgbString: rgbString, - rgbaString: rgbaString, - percentString: percentString, - percentaString: percentaString, - hslString: hslString, - hslaString: hslaString, - hwbString: hwbString, - keyword: keyword - } - - function getRgba(string) { - if (!string) { - return; - } - var abbr = /^#([a-fA-F0-9]{3})$/i, - hex = /^#([a-fA-F0-9]{6})$/i, - rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i, - per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i, - keyword = /(\w+)/; - - var rgb = [0, 0, 0], - a = 1, - match = string.match(abbr); - if (match) { - match = match[1]; - for (var i = 0; i < rgb.length; i++) { - rgb[i] = parseInt(match[i] + match[i], 16); - } - } - else if (match = string.match(hex)) { - match = match[1]; - for (var i = 0; i < rgb.length; i++) { - rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16); - } - } - else if (match = string.match(rgba)) { - for (var i = 0; i < rgb.length; i++) { - rgb[i] = parseInt(match[i + 1]); - } - a = parseFloat(match[4]); - } - else if (match = string.match(per)) { - for (var i = 0; i < rgb.length; i++) { - rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55); - } - a = parseFloat(match[4]); - } - else if (match = string.match(keyword)) { - if (match[1] == "transparent") { - return [0, 0, 0, 0]; - } - rgb = colorNames[match[1]]; - if (!rgb) { - return; - } - } - - for (var i = 0; i < rgb.length; i++) { - rgb[i] = scale(rgb[i], 0, 255); - } - if (!a && a != 0) { - a = 1; - } - else { - a = scale(a, 0, 1); - } - rgb[3] = a; - return rgb; - } - - function getHsla(string) { - if (!string) { - return; - } - var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/; - var match = string.match(hsl); - if (match) { - var alpha = parseFloat(match[4]); - var h = scale(parseInt(match[1]), 0, 360), - s = scale(parseFloat(match[2]), 0, 100), - l = scale(parseFloat(match[3]), 0, 100), - a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); - return [h, s, l, a]; - } - } - - function getHwb(string) { - if (!string) { - return; - } - var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/; - var match = string.match(hwb); - if (match) { - var alpha = parseFloat(match[4]); - var h = scale(parseInt(match[1]), 0, 360), - w = scale(parseFloat(match[2]), 0, 100), - b = scale(parseFloat(match[3]), 0, 100), - a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); - return [h, w, b, a]; - } - } - - function getRgb(string) { - var rgba = getRgba(string); - return rgba && rgba.slice(0, 3); - } - - function getHsl(string) { - var hsla = getHsla(string); - return hsla && hsla.slice(0, 3); - } - - function getAlpha(string) { - var vals = getRgba(string); - if (vals) { - return vals[3]; - } - else if (vals = getHsla(string)) { - return vals[3]; - } - else if (vals = getHwb(string)) { - return vals[3]; - } - } - - // generators - function hexString(rgb) { - return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1]) - + hexDouble(rgb[2]); - } - - function rgbString(rgba, alpha) { - if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { - return rgbaString(rgba, alpha); - } - return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")"; - } - - function rgbaString(rgba, alpha) { - if (alpha === undefined) { - alpha = (rgba[3] !== undefined ? rgba[3] : 1); - } - return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] - + ", " + alpha + ")"; - } - - function percentString(rgba, alpha) { - if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { - return percentaString(rgba, alpha); - } - var r = Math.round(rgba[0] / 255 * 100), - g = Math.round(rgba[1] / 255 * 100), - b = Math.round(rgba[2] / 255 * 100); - - return "rgb(" + r + "%, " + g + "%, " + b + "%)"; - } - - function percentaString(rgba, alpha) { - var r = Math.round(rgba[0] / 255 * 100), - g = Math.round(rgba[1] / 255 * 100), - b = Math.round(rgba[2] / 255 * 100); - return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")"; - } - - function hslString(hsla, alpha) { - if (alpha < 1 || (hsla[3] && hsla[3] < 1)) { - return hslaString(hsla, alpha); - } - return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)"; - } - - function hslaString(hsla, alpha) { - if (alpha === undefined) { - alpha = (hsla[3] !== undefined ? hsla[3] : 1); - } - return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " - + alpha + ")"; - } - - // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax - // (hwb have alpha optional & 1 is default value) - function hwbString(hwb, alpha) { - if (alpha === undefined) { - alpha = (hwb[3] !== undefined ? hwb[3] : 1); - } - return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%" - + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")"; - } - - function keyword(rgb) { - return reverseNames[rgb.slice(0, 3)]; - } - - // helpers - function scale(num, min, max) { - return Math.min(Math.max(min, num), max); - } - - function hexDouble(num) { - var str = num.toString(16).toUpperCase(); - return (str.length < 2) ? "0" + str : str; - } - - - //create a list of reverse color names - var reverseNames = {}; - for (var name in colorNames) { - reverseNames[colorNames[name]] = name; - } - - }, { "5": 5 }], 2: [function (require, module, exports) { - /* MIT license */ - var convert = require(4); - var string = require(1); - - var Color = function (obj) { - if (obj instanceof Color) { - return obj; - } - if (!(this instanceof Color)) { - return new Color(obj); - } - - this.valid = false; - this.values = { - rgb: [0, 0, 0], - hsl: [0, 0, 0], - hsv: [0, 0, 0], - hwb: [0, 0, 0], - cmyk: [0, 0, 0, 0], - alpha: 1 - }; - - // parse Color() argument - var vals; - if (typeof obj === 'string') { - vals = string.getRgba(obj); - if (vals) { - this.setValues('rgb', vals); - } else if (vals = string.getHsla(obj)) { - this.setValues('hsl', vals); - } else if (vals = string.getHwb(obj)) { - this.setValues('hwb', vals); - } - } else if (typeof obj === 'object') { - vals = obj; - if (vals.r !== undefined || vals.red !== undefined) { - this.setValues('rgb', vals); - } else if (vals.l !== undefined || vals.lightness !== undefined) { - this.setValues('hsl', vals); - } else if (vals.v !== undefined || vals.value !== undefined) { - this.setValues('hsv', vals); - } else if (vals.w !== undefined || vals.whiteness !== undefined) { - this.setValues('hwb', vals); - } else if (vals.c !== undefined || vals.cyan !== undefined) { - this.setValues('cmyk', vals); - } - } - }; - - Color.prototype = { - isValid: function () { - return this.valid; - }, - rgb: function () { - return this.setSpace('rgb', arguments); - }, - hsl: function () { - return this.setSpace('hsl', arguments); - }, - hsv: function () { - return this.setSpace('hsv', arguments); - }, - hwb: function () { - return this.setSpace('hwb', arguments); - }, - cmyk: function () { - return this.setSpace('cmyk', arguments); - }, - - rgbArray: function () { - return this.values.rgb; - }, - hslArray: function () { - return this.values.hsl; - }, - hsvArray: function () { - return this.values.hsv; - }, - hwbArray: function () { - var values = this.values; - if (values.alpha !== 1) { - return values.hwb.concat([values.alpha]); - } - return values.hwb; - }, - cmykArray: function () { - return this.values.cmyk; - }, - rgbaArray: function () { - var values = this.values; - return values.rgb.concat([values.alpha]); - }, - hslaArray: function () { - var values = this.values; - return values.hsl.concat([values.alpha]); - }, - alpha: function (val) { - if (val === undefined) { - return this.values.alpha; - } - this.setValues('alpha', val); - return this; - }, - - red: function (val) { - return this.setChannel('rgb', 0, val); - }, - green: function (val) { - return this.setChannel('rgb', 1, val); - }, - blue: function (val) { - return this.setChannel('rgb', 2, val); - }, - hue: function (val) { - if (val) { - val %= 360; - val = val < 0 ? 360 + val : val; - } - return this.setChannel('hsl', 0, val); - }, - saturation: function (val) { - return this.setChannel('hsl', 1, val); - }, - lightness: function (val) { - return this.setChannel('hsl', 2, val); - }, - saturationv: function (val) { - return this.setChannel('hsv', 1, val); - }, - whiteness: function (val) { - return this.setChannel('hwb', 1, val); - }, - blackness: function (val) { - return this.setChannel('hwb', 2, val); - }, - value: function (val) { - return this.setChannel('hsv', 2, val); - }, - cyan: function (val) { - return this.setChannel('cmyk', 0, val); - }, - magenta: function (val) { - return this.setChannel('cmyk', 1, val); - }, - yellow: function (val) { - return this.setChannel('cmyk', 2, val); - }, - black: function (val) { - return this.setChannel('cmyk', 3, val); - }, - - hexString: function () { - return string.hexString(this.values.rgb); - }, - rgbString: function () { - return string.rgbString(this.values.rgb, this.values.alpha); - }, - rgbaString: function () { - return string.rgbaString(this.values.rgb, this.values.alpha); - }, - percentString: function () { - return string.percentString(this.values.rgb, this.values.alpha); - }, - hslString: function () { - return string.hslString(this.values.hsl, this.values.alpha); - }, - hslaString: function () { - return string.hslaString(this.values.hsl, this.values.alpha); - }, - hwbString: function () { - return string.hwbString(this.values.hwb, this.values.alpha); - }, - keyword: function () { - return string.keyword(this.values.rgb, this.values.alpha); - }, - - rgbNumber: function () { - var rgb = this.values.rgb; - return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; - }, - - luminosity: function () { - // http://www.w3.org/TR/WCAG20/#relativeluminancedef - var rgb = this.values.rgb; - var lum = []; - for (var i = 0; i < rgb.length; i++) { - var chan = rgb[i] / 255; - lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4); - } - return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2]; - }, - - contrast: function (color2) { - // http://www.w3.org/TR/WCAG20/#contrast-ratiodef - var lum1 = this.luminosity(); - var lum2 = color2.luminosity(); - if (lum1 > lum2) { - return (lum1 + 0.05) / (lum2 + 0.05); - } - return (lum2 + 0.05) / (lum1 + 0.05); - }, - - level: function (color2) { - var contrastRatio = this.contrast(color2); - if (contrastRatio >= 7.1) { - return 'AAA'; - } - - return (contrastRatio >= 4.5) ? 'AA' : ''; - }, - - dark: function () { - // YIQ equation from http://24ways.org/2010/calculating-color-contrast - var rgb = this.values.rgb; - var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; - return yiq < 128; - }, - - light: function () { - return !this.dark(); - }, - - negate: function () { - var rgb = []; - for (var i = 0; i < 3; i++) { - rgb[i] = 255 - this.values.rgb[i]; - } - this.setValues('rgb', rgb); - return this; - }, - - lighten: function (ratio) { - var hsl = this.values.hsl; - hsl[2] += hsl[2] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - darken: function (ratio) { - var hsl = this.values.hsl; - hsl[2] -= hsl[2] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - saturate: function (ratio) { - var hsl = this.values.hsl; - hsl[1] += hsl[1] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - desaturate: function (ratio) { - var hsl = this.values.hsl; - hsl[1] -= hsl[1] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - whiten: function (ratio) { - var hwb = this.values.hwb; - hwb[1] += hwb[1] * ratio; - this.setValues('hwb', hwb); - return this; - }, - - blacken: function (ratio) { - var hwb = this.values.hwb; - hwb[2] += hwb[2] * ratio; - this.setValues('hwb', hwb); - return this; - }, - - greyscale: function () { - var rgb = this.values.rgb; - // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale - var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; - this.setValues('rgb', [val, val, val]); - return this; - }, - - clearer: function (ratio) { - var alpha = this.values.alpha; - this.setValues('alpha', alpha - (alpha * ratio)); - return this; - }, - - opaquer: function (ratio) { - var alpha = this.values.alpha; - this.setValues('alpha', alpha + (alpha * ratio)); - return this; - }, - - rotate: function (degrees) { - var hsl = this.values.hsl; - var hue = (hsl[0] + degrees) % 360; - hsl[0] = hue < 0 ? 360 + hue : hue; - this.setValues('hsl', hsl); - return this; - }, - - /** - * Ported from sass implementation in C - * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209 - */ - mix: function (mixinColor, weight) { - var color1 = this; - var color2 = mixinColor; - var p = weight === undefined ? 0.5 : weight; - - var w = 2 * p - 1; - var a = color1.alpha() - color2.alpha(); - - var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - var w2 = 1 - w1; - - return this - .rgb( - w1 * color1.red() + w2 * color2.red(), - w1 * color1.green() + w2 * color2.green(), - w1 * color1.blue() + w2 * color2.blue() - ) - .alpha(color1.alpha() * p + color2.alpha() * (1 - p)); - }, - - toJSON: function () { - return this.rgb(); - }, - - clone: function () { - // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify, - // making the final build way to big to embed in Chart.js. So let's do it manually, - // assuming that values to clone are 1 dimension arrays containing only numbers, - // except 'alpha' which is a number. - var result = new Color(); - var source = this.values; - var target = result.values; - var value, type; - - for (var prop in source) { - if (source.hasOwnProperty(prop)) { - value = source[prop]; - type = ({}).toString.call(value); - if (type === '[object Array]') { - target[prop] = value.slice(0); - } else if (type === '[object Number]') { - target[prop] = value; - } else { - console.error('unexpected color value:', value); - } - } - } - - return result; - } - }; - - Color.prototype.spaces = { - rgb: ['red', 'green', 'blue'], - hsl: ['hue', 'saturation', 'lightness'], - hsv: ['hue', 'saturation', 'value'], - hwb: ['hue', 'whiteness', 'blackness'], - cmyk: ['cyan', 'magenta', 'yellow', 'black'] - }; - - Color.prototype.maxes = { - rgb: [255, 255, 255], - hsl: [360, 100, 100], - hsv: [360, 100, 100], - hwb: [360, 100, 100], - cmyk: [100, 100, 100, 100] - }; - - Color.prototype.getValues = function (space) { - var values = this.values; - var vals = {}; - - for (var i = 0; i < space.length; i++) { - vals[space.charAt(i)] = values[space][i]; - } - - if (values.alpha !== 1) { - vals.a = values.alpha; - } - - // {r: 255, g: 255, b: 255, a: 0.4} - return vals; - }; - - Color.prototype.setValues = function (space, vals) { - var values = this.values; - var spaces = this.spaces; - var maxes = this.maxes; - var alpha = 1; - var i; - - this.valid = true; - - if (space === 'alpha') { - alpha = vals; - } else if (vals.length) { - // [10, 10, 10] - values[space] = vals.slice(0, space.length); - alpha = vals[space.length]; - } else if (vals[space.charAt(0)] !== undefined) { - // {r: 10, g: 10, b: 10} - for (i = 0; i < space.length; i++) { - values[space][i] = vals[space.charAt(i)]; - } - - alpha = vals.a; - } else if (vals[spaces[space][0]] !== undefined) { - // {red: 10, green: 10, blue: 10} - var chans = spaces[space]; - - for (i = 0; i < space.length; i++) { - values[space][i] = vals[chans[i]]; - } - - alpha = vals.alpha; - } - - values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha))); - - if (space === 'alpha') { - return false; - } - - var capped; - - // cap values of the space prior converting all values - for (i = 0; i < space.length; i++) { - capped = Math.max(0, Math.min(maxes[space][i], values[space][i])); - values[space][i] = Math.round(capped); - } - - // convert to all the other color spaces - for (var sname in spaces) { - if (sname !== space) { - values[sname] = convert[space][sname](values[space]); - } - } - - return true; - }; - - Color.prototype.setSpace = function (space, args) { - var vals = args[0]; - - if (vals === undefined) { - // color.rgb() - return this.getValues(space); - } - - // color.rgb(10, 10, 10) - if (typeof vals === 'number') { - vals = Array.prototype.slice.call(args); - } - - this.setValues(space, vals); - return this; - }; - - Color.prototype.setChannel = function (space, index, val) { - var svalues = this.values[space]; - if (val === undefined) { - // color.red() - return svalues[index]; - } else if (val === svalues[index]) { - // color.red(color.red()) - return this; - } - - // color.red(100) - svalues[index] = val; - this.setValues(space, svalues); - - return this; - }; - - if (typeof window !== 'undefined') { - window.Color = Color; - } - - module.exports = Color; - - }, { "1": 1, "4": 4 }], 3: [function (require, module, exports) { - /* MIT license */ - - module.exports = { - rgb2hsl: rgb2hsl, - rgb2hsv: rgb2hsv, - rgb2hwb: rgb2hwb, - rgb2cmyk: rgb2cmyk, - rgb2keyword: rgb2keyword, - rgb2xyz: rgb2xyz, - rgb2lab: rgb2lab, - rgb2lch: rgb2lch, - - hsl2rgb: hsl2rgb, - hsl2hsv: hsl2hsv, - hsl2hwb: hsl2hwb, - hsl2cmyk: hsl2cmyk, - hsl2keyword: hsl2keyword, - - hsv2rgb: hsv2rgb, - hsv2hsl: hsv2hsl, - hsv2hwb: hsv2hwb, - hsv2cmyk: hsv2cmyk, - hsv2keyword: hsv2keyword, - - hwb2rgb: hwb2rgb, - hwb2hsl: hwb2hsl, - hwb2hsv: hwb2hsv, - hwb2cmyk: hwb2cmyk, - hwb2keyword: hwb2keyword, - - cmyk2rgb: cmyk2rgb, - cmyk2hsl: cmyk2hsl, - cmyk2hsv: cmyk2hsv, - cmyk2hwb: cmyk2hwb, - cmyk2keyword: cmyk2keyword, - - keyword2rgb: keyword2rgb, - keyword2hsl: keyword2hsl, - keyword2hsv: keyword2hsv, - keyword2hwb: keyword2hwb, - keyword2cmyk: keyword2cmyk, - keyword2lab: keyword2lab, - keyword2xyz: keyword2xyz, - - xyz2rgb: xyz2rgb, - xyz2lab: xyz2lab, - xyz2lch: xyz2lch, - - lab2xyz: lab2xyz, - lab2rgb: lab2rgb, - lab2lch: lab2lch, - - lch2lab: lch2lab, - lch2xyz: lch2xyz, - lch2rgb: lch2rgb - } - - - function rgb2hsl(rgb) { - var r = rgb[0] / 255, - g = rgb[1] / 255, - b = rgb[2] / 255, - min = Math.min(r, g, b), - max = Math.max(r, g, b), - delta = max - min, - h, s, l; - - if (max == min) - h = 0; - else if (r == max) - h = (g - b) / delta; - else if (g == max) - h = 2 + (b - r) / delta; - else if (b == max) - h = 4 + (r - g) / delta; - - h = Math.min(h * 60, 360); - - if (h < 0) - h += 360; - - l = (min + max) / 2; - - if (max == min) - s = 0; - else if (l <= 0.5) - s = delta / (max + min); - else - s = delta / (2 - max - min); - - return [h, s * 100, l * 100]; - } - - function rgb2hsv(rgb) { - var r = rgb[0], - g = rgb[1], - b = rgb[2], - min = Math.min(r, g, b), - max = Math.max(r, g, b), - delta = max - min, - h, s, v; - - if (max == 0) - s = 0; - else - s = (delta / max * 1000) / 10; - - if (max == min) - h = 0; - else if (r == max) - h = (g - b) / delta; - else if (g == max) - h = 2 + (b - r) / delta; - else if (b == max) - h = 4 + (r - g) / delta; - - h = Math.min(h * 60, 360); - - if (h < 0) - h += 360; - - v = ((max / 255) * 1000) / 10; - - return [h, s, v]; - } - - function rgb2hwb(rgb) { - var r = rgb[0], - g = rgb[1], - b = rgb[2], - h = rgb2hsl(rgb)[0], - w = 1 / 255 * Math.min(r, Math.min(g, b)), - b = 1 - 1 / 255 * Math.max(r, Math.max(g, b)); - - return [h, w * 100, b * 100]; - } - - function rgb2cmyk(rgb) { - var r = rgb[0] / 255, - g = rgb[1] / 255, - b = rgb[2] / 255, - c, m, y, k; - - k = Math.min(1 - r, 1 - g, 1 - b); - c = (1 - r - k) / (1 - k) || 0; - m = (1 - g - k) / (1 - k) || 0; - y = (1 - b - k) / (1 - k) || 0; - return [c * 100, m * 100, y * 100, k * 100]; - } - - function rgb2keyword(rgb) { - return reverseKeywords[JSON.stringify(rgb)]; - } - - function rgb2xyz(rgb) { - var r = rgb[0] / 255, - g = rgb[1] / 255, - b = rgb[2] / 255; - - // assume sRGB - r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); - g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); - b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); - - var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); - var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); - var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); - - return [x * 100, y * 100, z * 100]; - } - - function rgb2lab(rgb) { - var xyz = rgb2xyz(rgb), - x = xyz[0], - y = xyz[1], - z = xyz[2], - l, a, b; - - x /= 95.047; - y /= 100; - z /= 108.883; - - x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116); - y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116); - z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116); - - l = (116 * y) - 16; - a = 500 * (x - y); - b = 200 * (y - z); - - return [l, a, b]; - } - - function rgb2lch(args) { - return lab2lch(rgb2lab(args)); - } - - function hsl2rgb(hsl) { - var h = hsl[0] / 360, - s = hsl[1] / 100, - l = hsl[2] / 100, - t1, t2, t3, rgb, val; - - if (s == 0) { - val = l * 255; - return [val, val, val]; - } - - if (l < 0.5) - t2 = l * (1 + s); - else - t2 = l + s - l * s; - t1 = 2 * l - t2; - - rgb = [0, 0, 0]; - for (var i = 0; i < 3; i++) { - t3 = h + 1 / 3 * - (i - 1); - t3 < 0 && t3++; - t3 > 1 && t3--; - - if (6 * t3 < 1) - val = t1 + (t2 - t1) * 6 * t3; - else if (2 * t3 < 1) - val = t2; - else if (3 * t3 < 2) - val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; - else - val = t1; - - rgb[i] = val * 255; - } - - return rgb; - } - - function hsl2hsv(hsl) { - var h = hsl[0], - s = hsl[1] / 100, - l = hsl[2] / 100, - sv, v; - - if (l === 0) { - // no need to do calc on black - // also avoids divide by 0 error - return [0, 0, 0]; - } - - l *= 2; - s *= (l <= 1) ? l : 2 - l; - v = (l + s) / 2; - sv = (2 * s) / (l + s); - return [h, sv * 100, v * 100]; - } - - function hsl2hwb(args) { - return rgb2hwb(hsl2rgb(args)); - } - - function hsl2cmyk(args) { - return rgb2cmyk(hsl2rgb(args)); - } - - function hsl2keyword(args) { - return rgb2keyword(hsl2rgb(args)); - } - - - function hsv2rgb(hsv) { - var h = hsv[0] / 60, - s = hsv[1] / 100, - v = hsv[2] / 100, - hi = Math.floor(h) % 6; - - var f = h - Math.floor(h), - p = 255 * v * (1 - s), - q = 255 * v * (1 - (s * f)), - t = 255 * v * (1 - (s * (1 - f))), - v = 255 * v; - - switch (hi) { - case 0: - return [v, t, p]; - case 1: - return [q, v, p]; - case 2: - return [p, v, t]; - case 3: - return [p, q, v]; - case 4: - return [t, p, v]; - case 5: - return [v, p, q]; - } - } - - function hsv2hsl(hsv) { - var h = hsv[0], - s = hsv[1] / 100, - v = hsv[2] / 100, - sl, l; - - l = (2 - s) * v; - sl = s * v; - sl /= (l <= 1) ? l : 2 - l; - sl = sl || 0; - l /= 2; - return [h, sl * 100, l * 100]; - } - - function hsv2hwb(args) { - return rgb2hwb(hsv2rgb(args)) - } - - function hsv2cmyk(args) { - return rgb2cmyk(hsv2rgb(args)); - } - - function hsv2keyword(args) { - return rgb2keyword(hsv2rgb(args)); - } - - // http://dev.w3.org/csswg/css-color/#hwb-to-rgb - function hwb2rgb(hwb) { - var h = hwb[0] / 360, - wh = hwb[1] / 100, - bl = hwb[2] / 100, - ratio = wh + bl, - i, v, f, n; - - // wh + bl cant be > 1 - if (ratio > 1) { - wh /= ratio; - bl /= ratio; - } - - i = Math.floor(6 * h); - v = 1 - bl; - f = 6 * h - i; - if ((i & 0x01) != 0) { - f = 1 - f; - } - n = wh + f * (v - wh); // linear interpolation - - switch (i) { - default: - case 6: - case 0: r = v; g = n; b = wh; break; - case 1: r = n; g = v; b = wh; break; - case 2: r = wh; g = v; b = n; break; - case 3: r = wh; g = n; b = v; break; - case 4: r = n; g = wh; b = v; break; - case 5: r = v; g = wh; b = n; break; - } - - return [r * 255, g * 255, b * 255]; - } - - function hwb2hsl(args) { - return rgb2hsl(hwb2rgb(args)); - } - - function hwb2hsv(args) { - return rgb2hsv(hwb2rgb(args)); - } - - function hwb2cmyk(args) { - return rgb2cmyk(hwb2rgb(args)); - } - - function hwb2keyword(args) { - return rgb2keyword(hwb2rgb(args)); - } - - function cmyk2rgb(cmyk) { - var c = cmyk[0] / 100, - m = cmyk[1] / 100, - y = cmyk[2] / 100, - k = cmyk[3] / 100, - r, g, b; - - r = 1 - Math.min(1, c * (1 - k) + k); - g = 1 - Math.min(1, m * (1 - k) + k); - b = 1 - Math.min(1, y * (1 - k) + k); - return [r * 255, g * 255, b * 255]; - } - - function cmyk2hsl(args) { - return rgb2hsl(cmyk2rgb(args)); - } - - function cmyk2hsv(args) { - return rgb2hsv(cmyk2rgb(args)); - } - - function cmyk2hwb(args) { - return rgb2hwb(cmyk2rgb(args)); - } - - function cmyk2keyword(args) { - return rgb2keyword(cmyk2rgb(args)); - } - - - function xyz2rgb(xyz) { - var x = xyz[0] / 100, - y = xyz[1] / 100, - z = xyz[2] / 100, - r, g, b; - - r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); - g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); - b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); - - // assume sRGB - r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) - : r = (r * 12.92); - - g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) - : g = (g * 12.92); - - b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) - : b = (b * 12.92); - - r = Math.min(Math.max(0, r), 1); - g = Math.min(Math.max(0, g), 1); - b = Math.min(Math.max(0, b), 1); - - return [r * 255, g * 255, b * 255]; - } - - function xyz2lab(xyz) { - var x = xyz[0], - y = xyz[1], - z = xyz[2], - l, a, b; - - x /= 95.047; - y /= 100; - z /= 108.883; - - x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116); - y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116); - z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116); - - l = (116 * y) - 16; - a = 500 * (x - y); - b = 200 * (y - z); - - return [l, a, b]; - } - - function xyz2lch(args) { - return lab2lch(xyz2lab(args)); - } - - function lab2xyz(lab) { - var l = lab[0], - a = lab[1], - b = lab[2], - x, y, z, y2; - - if (l <= 8) { - y = (l * 100) / 903.3; - y2 = (7.787 * (y / 100)) + (16 / 116); - } else { - y = 100 * Math.pow((l + 16) / 116, 3); - y2 = Math.pow(y / 100, 1 / 3); - } - - x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3); - - z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3); - - return [x, y, z]; - } - - function lab2lch(lab) { - var l = lab[0], - a = lab[1], - b = lab[2], - hr, h, c; - - hr = Math.atan2(b, a); - h = hr * 360 / 2 / Math.PI; - if (h < 0) { - h += 360; - } - c = Math.sqrt(a * a + b * b); - return [l, c, h]; - } - - function lab2rgb(args) { - return xyz2rgb(lab2xyz(args)); - } - - function lch2lab(lch) { - var l = lch[0], - c = lch[1], - h = lch[2], - a, b, hr; - - hr = h / 360 * 2 * Math.PI; - a = c * Math.cos(hr); - b = c * Math.sin(hr); - return [l, a, b]; - } - - function lch2xyz(args) { - return lab2xyz(lch2lab(args)); - } - - function lch2rgb(args) { - return lab2rgb(lch2lab(args)); - } - - function keyword2rgb(keyword) { - return cssKeywords[keyword]; - } - - function keyword2hsl(args) { - return rgb2hsl(keyword2rgb(args)); - } - - function keyword2hsv(args) { - return rgb2hsv(keyword2rgb(args)); - } - - function keyword2hwb(args) { - return rgb2hwb(keyword2rgb(args)); - } - - function keyword2cmyk(args) { - return rgb2cmyk(keyword2rgb(args)); - } - - function keyword2lab(args) { - return rgb2lab(keyword2rgb(args)); - } - - function keyword2xyz(args) { - return rgb2xyz(keyword2rgb(args)); - } - - var cssKeywords = { - aliceblue: [240, 248, 255], - antiquewhite: [250, 235, 215], - aqua: [0, 255, 255], - aquamarine: [127, 255, 212], - azure: [240, 255, 255], - beige: [245, 245, 220], - bisque: [255, 228, 196], - black: [0, 0, 0], - blanchedalmond: [255, 235, 205], - blue: [0, 0, 255], - blueviolet: [138, 43, 226], - brown: [165, 42, 42], - burlywood: [222, 184, 135], - cadetblue: [95, 158, 160], - chartreuse: [127, 255, 0], - chocolate: [210, 105, 30], - coral: [255, 127, 80], - cornflowerblue: [100, 149, 237], - cornsilk: [255, 248, 220], - crimson: [220, 20, 60], - cyan: [0, 255, 255], - darkblue: [0, 0, 139], - darkcyan: [0, 139, 139], - darkgoldenrod: [184, 134, 11], - darkgray: [169, 169, 169], - darkgreen: [0, 100, 0], - darkgrey: [169, 169, 169], - darkkhaki: [189, 183, 107], - darkmagenta: [139, 0, 139], - darkolivegreen: [85, 107, 47], - darkorange: [255, 140, 0], - darkorchid: [153, 50, 204], - darkred: [139, 0, 0], - darksalmon: [233, 150, 122], - darkseagreen: [143, 188, 143], - darkslateblue: [72, 61, 139], - darkslategray: [47, 79, 79], - darkslategrey: [47, 79, 79], - darkturquoise: [0, 206, 209], - darkviolet: [148, 0, 211], - deeppink: [255, 20, 147], - deepskyblue: [0, 191, 255], - dimgray: [105, 105, 105], - dimgrey: [105, 105, 105], - dodgerblue: [30, 144, 255], - firebrick: [178, 34, 34], - floralwhite: [255, 250, 240], - forestgreen: [34, 139, 34], - fuchsia: [255, 0, 255], - gainsboro: [220, 220, 220], - ghostwhite: [248, 248, 255], - gold: [255, 215, 0], - goldenrod: [218, 165, 32], - gray: [128, 128, 128], - green: [0, 128, 0], - greenyellow: [173, 255, 47], - grey: [128, 128, 128], - honeydew: [240, 255, 240], - hotpink: [255, 105, 180], - indianred: [205, 92, 92], - indigo: [75, 0, 130], - ivory: [255, 255, 240], - khaki: [240, 230, 140], - lavender: [230, 230, 250], - lavenderblush: [255, 240, 245], - lawngreen: [124, 252, 0], - lemonchiffon: [255, 250, 205], - lightblue: [173, 216, 230], - lightcoral: [240, 128, 128], - lightcyan: [224, 255, 255], - lightgoldenrodyellow: [250, 250, 210], - lightgray: [211, 211, 211], - lightgreen: [144, 238, 144], - lightgrey: [211, 211, 211], - lightpink: [255, 182, 193], - lightsalmon: [255, 160, 122], - lightseagreen: [32, 178, 170], - lightskyblue: [135, 206, 250], - lightslategray: [119, 136, 153], - lightslategrey: [119, 136, 153], - lightsteelblue: [176, 196, 222], - lightyellow: [255, 255, 224], - lime: [0, 255, 0], - limegreen: [50, 205, 50], - linen: [250, 240, 230], - magenta: [255, 0, 255], - maroon: [128, 0, 0], - mediumaquamarine: [102, 205, 170], - mediumblue: [0, 0, 205], - mediumorchid: [186, 85, 211], - mediumpurple: [147, 112, 219], - mediumseagreen: [60, 179, 113], - mediumslateblue: [123, 104, 238], - mediumspringgreen: [0, 250, 154], - mediumturquoise: [72, 209, 204], - mediumvioletred: [199, 21, 133], - midnightblue: [25, 25, 112], - mintcream: [245, 255, 250], - mistyrose: [255, 228, 225], - moccasin: [255, 228, 181], - navajowhite: [255, 222, 173], - navy: [0, 0, 128], - oldlace: [253, 245, 230], - olive: [128, 128, 0], - olivedrab: [107, 142, 35], - orange: [255, 165, 0], - orangered: [255, 69, 0], - orchid: [218, 112, 214], - palegoldenrod: [238, 232, 170], - palegreen: [152, 251, 152], - paleturquoise: [175, 238, 238], - palevioletred: [219, 112, 147], - papayawhip: [255, 239, 213], - peachpuff: [255, 218, 185], - peru: [205, 133, 63], - pink: [255, 192, 203], - plum: [221, 160, 221], - powderblue: [176, 224, 230], - purple: [128, 0, 128], - rebeccapurple: [102, 51, 153], - red: [255, 0, 0], - rosybrown: [188, 143, 143], - royalblue: [65, 105, 225], - saddlebrown: [139, 69, 19], - salmon: [250, 128, 114], - sandybrown: [244, 164, 96], - seagreen: [46, 139, 87], - seashell: [255, 245, 238], - sienna: [160, 82, 45], - silver: [192, 192, 192], - skyblue: [135, 206, 235], - slateblue: [106, 90, 205], - slategray: [112, 128, 144], - slategrey: [112, 128, 144], - snow: [255, 250, 250], - springgreen: [0, 255, 127], - steelblue: [70, 130, 180], - tan: [210, 180, 140], - teal: [0, 128, 128], - thistle: [216, 191, 216], - tomato: [255, 99, 71], - turquoise: [64, 224, 208], - violet: [238, 130, 238], - wheat: [245, 222, 179], - white: [255, 255, 255], - whitesmoke: [245, 245, 245], - yellow: [255, 255, 0], - yellowgreen: [154, 205, 50] - }; - - var reverseKeywords = {}; - for (var key in cssKeywords) { - reverseKeywords[JSON.stringify(cssKeywords[key])] = key; - } - - }, {}], 4: [function (require, module, exports) { - var conversions = require(3); - - var convert = function () { - return new Converter(); - } - - for (var func in conversions) { - // export Raw versions - convert[func + "Raw"] = (function (func) { - // accept array or plain args - return function (arg) { - if (typeof arg == "number") - arg = Array.prototype.slice.call(arguments); - return conversions[func](arg); - } - })(func); - - var pair = /(\w+)2(\w+)/.exec(func), - from = pair[1], - to = pair[2]; - - // export rgb2hsl and ["rgb"]["hsl"] - convert[from] = convert[from] || {}; - - convert[from][to] = convert[func] = (function (func) { - return function (arg) { - if (typeof arg == "number") - arg = Array.prototype.slice.call(arguments); - - var val = conversions[func](arg); - if (typeof val == "string" || val === undefined) - return val; // keyword - - for (var i = 0; i < val.length; i++) - val[i] = Math.round(val[i]); - return val; - } - })(func); - } - - - /* Converter does lazy conversion and caching */ - var Converter = function () { - this.convs = {}; - }; - - /* Either get the values for a space or - set the values for a space, depending on args */ - Converter.prototype.routeSpace = function (space, args) { - var values = args[0]; - if (values === undefined) { - // color.rgb() - return this.getValues(space); - } - // color.rgb(10, 10, 10) - if (typeof values == "number") { - values = Array.prototype.slice.call(args); - } - - return this.setValues(space, values); - }; - - /* Set the values for a space, invalidating cache */ - Converter.prototype.setValues = function (space, values) { - this.space = space; - this.convs = {}; - this.convs[space] = values; - return this; - }; - - /* Get the values for a space. If there's already - a conversion for the space, fetch it, otherwise - compute it */ - Converter.prototype.getValues = function (space) { - var vals = this.convs[space]; - if (!vals) { - var fspace = this.space, - from = this.convs[fspace]; - vals = convert[fspace][space](from); - - this.convs[space] = vals; - } - return vals; - }; - - ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function (space) { - Converter.prototype[space] = function (vals) { - return this.routeSpace(space, arguments); - } - }); - - module.exports = convert; - }, { "3": 3 }], 5: [function (require, module, exports) { - 'use strict' - - module.exports = { - "aliceblue": [240, 248, 255], - "antiquewhite": [250, 235, 215], - "aqua": [0, 255, 255], - "aquamarine": [127, 255, 212], - "azure": [240, 255, 255], - "beige": [245, 245, 220], - "bisque": [255, 228, 196], - "black": [0, 0, 0], - "blanchedalmond": [255, 235, 205], - "blue": [0, 0, 255], - "blueviolet": [138, 43, 226], - "brown": [165, 42, 42], - "burlywood": [222, 184, 135], - "cadetblue": [95, 158, 160], - "chartreuse": [127, 255, 0], - "chocolate": [210, 105, 30], - "coral": [255, 127, 80], - "cornflowerblue": [100, 149, 237], - "cornsilk": [255, 248, 220], - "crimson": [220, 20, 60], - "cyan": [0, 255, 255], - "darkblue": [0, 0, 139], - "darkcyan": [0, 139, 139], - "darkgoldenrod": [184, 134, 11], - "darkgray": [169, 169, 169], - "darkgreen": [0, 100, 0], - "darkgrey": [169, 169, 169], - "darkkhaki": [189, 183, 107], - "darkmagenta": [139, 0, 139], - "darkolivegreen": [85, 107, 47], - "darkorange": [255, 140, 0], - "darkorchid": [153, 50, 204], - "darkred": [139, 0, 0], - "darksalmon": [233, 150, 122], - "darkseagreen": [143, 188, 143], - "darkslateblue": [72, 61, 139], - "darkslategray": [47, 79, 79], - "darkslategrey": [47, 79, 79], - "darkturquoise": [0, 206, 209], - "darkviolet": [148, 0, 211], - "deeppink": [255, 20, 147], - "deepskyblue": [0, 191, 255], - "dimgray": [105, 105, 105], - "dimgrey": [105, 105, 105], - "dodgerblue": [30, 144, 255], - "firebrick": [178, 34, 34], - "floralwhite": [255, 250, 240], - "forestgreen": [34, 139, 34], - "fuchsia": [255, 0, 255], - "gainsboro": [220, 220, 220], - "ghostwhite": [248, 248, 255], - "gold": [255, 215, 0], - "goldenrod": [218, 165, 32], - "gray": [128, 128, 128], - "green": [0, 128, 0], - "greenyellow": [173, 255, 47], - "grey": [128, 128, 128], - "honeydew": [240, 255, 240], - "hotpink": [255, 105, 180], - "indianred": [205, 92, 92], - "indigo": [75, 0, 130], - "ivory": [255, 255, 240], - "khaki": [240, 230, 140], - "lavender": [230, 230, 250], - "lavenderblush": [255, 240, 245], - "lawngreen": [124, 252, 0], - "lemonchiffon": [255, 250, 205], - "lightblue": [173, 216, 230], - "lightcoral": [240, 128, 128], - "lightcyan": [224, 255, 255], - "lightgoldenrodyellow": [250, 250, 210], - "lightgray": [211, 211, 211], - "lightgreen": [144, 238, 144], - "lightgrey": [211, 211, 211], - "lightpink": [255, 182, 193], - "lightsalmon": [255, 160, 122], - "lightseagreen": [32, 178, 170], - "lightskyblue": [135, 206, 250], - "lightslategray": [119, 136, 153], - "lightslategrey": [119, 136, 153], - "lightsteelblue": [176, 196, 222], - "lightyellow": [255, 255, 224], - "lime": [0, 255, 0], - "limegreen": [50, 205, 50], - "linen": [250, 240, 230], - "magenta": [255, 0, 255], - "maroon": [128, 0, 0], - "mediumaquamarine": [102, 205, 170], - "mediumblue": [0, 0, 205], - "mediumorchid": [186, 85, 211], - "mediumpurple": [147, 112, 219], - "mediumseagreen": [60, 179, 113], - "mediumslateblue": [123, 104, 238], - "mediumspringgreen": [0, 250, 154], - "mediumturquoise": [72, 209, 204], - "mediumvioletred": [199, 21, 133], - "midnightblue": [25, 25, 112], - "mintcream": [245, 255, 250], - "mistyrose": [255, 228, 225], - "moccasin": [255, 228, 181], - "navajowhite": [255, 222, 173], - "navy": [0, 0, 128], - "oldlace": [253, 245, 230], - "olive": [128, 128, 0], - "olivedrab": [107, 142, 35], - "orange": [255, 165, 0], - "orangered": [255, 69, 0], - "orchid": [218, 112, 214], - "palegoldenrod": [238, 232, 170], - "palegreen": [152, 251, 152], - "paleturquoise": [175, 238, 238], - "palevioletred": [219, 112, 147], - "papayawhip": [255, 239, 213], - "peachpuff": [255, 218, 185], - "peru": [205, 133, 63], - "pink": [255, 192, 203], - "plum": [221, 160, 221], - "powderblue": [176, 224, 230], - "purple": [128, 0, 128], - "rebeccapurple": [102, 51, 153], - "red": [255, 0, 0], - "rosybrown": [188, 143, 143], - "royalblue": [65, 105, 225], - "saddlebrown": [139, 69, 19], - "salmon": [250, 128, 114], - "sandybrown": [244, 164, 96], - "seagreen": [46, 139, 87], - "seashell": [255, 245, 238], - "sienna": [160, 82, 45], - "silver": [192, 192, 192], - "skyblue": [135, 206, 235], - "slateblue": [106, 90, 205], - "slategray": [112, 128, 144], - "slategrey": [112, 128, 144], - "snow": [255, 250, 250], - "springgreen": [0, 255, 127], - "steelblue": [70, 130, 180], - "tan": [210, 180, 140], - "teal": [0, 128, 128], - "thistle": [216, 191, 216], - "tomato": [255, 99, 71], - "turquoise": [64, 224, 208], - "violet": [238, 130, 238], - "wheat": [245, 222, 179], - "white": [255, 255, 255], - "whitesmoke": [245, 245, 245], - "yellow": [255, 255, 0], - "yellowgreen": [154, 205, 50] - }; - - }, {}], 6: [function (require, module, exports) { - //! moment.js - //! version : 2.20.1 - //! authors : Tim Wood, Iskren Chernev, Moment.js contributors - //! license : MIT - //! momentjs.com - - ; (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - global.moment = factory() - } (this, (function () { - 'use strict'; - - var hookCallback; - - function hooks() { - return hookCallback.apply(null, arguments); - } - - // This is done to register the method called with moment() - // without creating circular dependencies. - function setHookCallback(callback) { - hookCallback = callback; - } - - function isArray(input) { - return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]'; - } - - function isObject(input) { - // IE8 will treat undefined and null as object if it wasn't for - // input != null - return input != null && Object.prototype.toString.call(input) === '[object Object]'; - } - - function isObjectEmpty(obj) { - if (Object.getOwnPropertyNames) { - return (Object.getOwnPropertyNames(obj).length === 0); - } else { - var k; - for (k in obj) { - if (obj.hasOwnProperty(k)) { - return false; - } - } - return true; - } - } - - function isUndefined(input) { - return input === void 0; - } - - function isNumber(input) { - return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]'; - } - - function isDate(input) { - return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]'; - } - - function map(arr, fn) { - var res = [], i; - for (i = 0; i < arr.length; ++i) { - res.push(fn(arr[i], i)); - } - return res; - } - - function hasOwnProp(a, b) { - return Object.prototype.hasOwnProperty.call(a, b); - } - - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } - } - - if (hasOwnProp(b, 'toString')) { - a.toString = b.toString; - } - - if (hasOwnProp(b, 'valueOf')) { - a.valueOf = b.valueOf; - } - - return a; - } - - function createUTC(input, format, locale, strict) { - return createLocalOrUTC(input, format, locale, strict, true).utc(); - } - - function defaultParsingFlags() { - // We need to deep clone this object. - return { - empty: false, - unusedTokens: [], - unusedInput: [], - overflow: -2, - charsLeftOver: 0, - nullInput: false, - invalidMonth: null, - invalidFormat: false, - userInvalidated: false, - iso: false, - parsedDateParts: [], - meridiem: null, - rfc2822: false, - weekdayMismatch: false - }; - } - - function getParsingFlags(m) { - if (m._pf == null) { - m._pf = defaultParsingFlags(); - } - return m._pf; - } - - var some; - if (Array.prototype.some) { - some = Array.prototype.some; - } else { - some = function (fun) { - var t = Object(this); - var len = t.length >>> 0; - - for (var i = 0; i < len; i++) { - if (i in t && fun.call(this, t[i], i, t)) { - return true; - } - } - - return false; - }; - } - - function isValid(m) { - if (m._isValid == null) { - var flags = getParsingFlags(m); - var parsedParts = some.call(flags.parsedDateParts, function (i) { - return i != null; - }); - var isNowValid = !isNaN(m._d.getTime()) && - flags.overflow < 0 && - !flags.empty && - !flags.invalidMonth && - !flags.invalidWeekday && - !flags.weekdayMismatch && - !flags.nullInput && - !flags.invalidFormat && - !flags.userInvalidated && - (!flags.meridiem || (flags.meridiem && parsedParts)); - - if (m._strict) { - isNowValid = isNowValid && - flags.charsLeftOver === 0 && - flags.unusedTokens.length === 0 && - flags.bigHour === undefined; - } - - if (Object.isFrozen == null || !Object.isFrozen(m)) { - m._isValid = isNowValid; - } - else { - return isNowValid; - } - } - return m._isValid; - } - - function createInvalid(flags) { - var m = createUTC(NaN); - if (flags != null) { - extend(getParsingFlags(m), flags); - } - else { - getParsingFlags(m).userInvalidated = true; - } - - return m; - } - - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - var momentProperties = hooks.momentProperties = []; - - function copyConfig(to, from) { - var i, prop, val; - - if (!isUndefined(from._isAMomentObject)) { - to._isAMomentObject = from._isAMomentObject; - } - if (!isUndefined(from._i)) { - to._i = from._i; - } - if (!isUndefined(from._f)) { - to._f = from._f; - } - if (!isUndefined(from._l)) { - to._l = from._l; - } - if (!isUndefined(from._strict)) { - to._strict = from._strict; - } - if (!isUndefined(from._tzm)) { - to._tzm = from._tzm; - } - if (!isUndefined(from._isUTC)) { - to._isUTC = from._isUTC; - } - if (!isUndefined(from._offset)) { - to._offset = from._offset; - } - if (!isUndefined(from._pf)) { - to._pf = getParsingFlags(from); - } - if (!isUndefined(from._locale)) { - to._locale = from._locale; - } - - if (momentProperties.length > 0) { - for (i = 0; i < momentProperties.length; i++) { - prop = momentProperties[i]; - val = from[prop]; - if (!isUndefined(val)) { - to[prop] = val; - } - } - } - - return to; - } - - var updateInProgress = false; - - // Moment prototype object - function Moment(config) { - copyConfig(this, config); - this._d = new Date(config._d != null ? config._d.getTime() : NaN); - if (!this.isValid()) { - this._d = new Date(NaN); - } - // Prevent infinite loop in case updateOffset creates new moment - // objects. - if (updateInProgress === false) { - updateInProgress = true; - hooks.updateOffset(this); - updateInProgress = false; - } - } - - function isMoment(obj) { - return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); - } - - function absFloor(number) { - if (number < 0) { - // -0 -> 0 - return Math.ceil(number) || 0; - } else { - return Math.floor(number); - } - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - value = absFloor(coercedNumber); - } - - return value; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function warn(msg) { - if (hooks.suppressDeprecationWarnings === false && - (typeof console !== 'undefined') && console.warn) { - console.warn('Deprecation warning: ' + msg); - } - } - - function deprecate(msg, fn) { - var firstTime = true; - - return extend(function () { - if (hooks.deprecationHandler != null) { - hooks.deprecationHandler(null, msg); - } - if (firstTime) { - var args = []; - var arg; - for (var i = 0; i < arguments.length; i++) { - arg = ''; - if (typeof arguments[i] === 'object') { - arg += '\n[' + i + '] '; - for (var key in arguments[0]) { - arg += key + ': ' + arguments[0][key] + ', '; - } - arg = arg.slice(0, -2); // Remove trailing comma and space - } else { - arg = arguments[i]; - } - args.push(arg); - } - warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); - } - - var deprecations = {}; - - function deprecateSimple(name, msg) { - if (hooks.deprecationHandler != null) { - hooks.deprecationHandler(name, msg); - } - if (!deprecations[name]) { - warn(msg); - deprecations[name] = true; - } - } - - hooks.suppressDeprecationWarnings = false; - hooks.deprecationHandler = null; - - function isFunction(input) { - return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]'; - } - - function set(config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (isFunction(prop)) { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - this._config = config; - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _dayOfMonthOrdinalParse. - // TODO: Remove "ordinalParse" fallback in next major release. - this._dayOfMonthOrdinalParseLenient = new RegExp( - (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + - '|' + (/\d{1,2}/).source); - } - - function mergeConfigs(parentConfig, childConfig) { - var res = extend({}, parentConfig), prop; - for (prop in childConfig) { - if (hasOwnProp(childConfig, prop)) { - if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { - res[prop] = {}; - extend(res[prop], parentConfig[prop]); - extend(res[prop], childConfig[prop]); - } else if (childConfig[prop] != null) { - res[prop] = childConfig[prop]; - } else { - delete res[prop]; - } - } - } - for (prop in parentConfig) { - if (hasOwnProp(parentConfig, prop) && - !hasOwnProp(childConfig, prop) && - isObject(parentConfig[prop])) { - // make sure changes to properties don't modify parent config - res[prop] = extend({}, res[prop]); - } - } - return res; - } - - function Locale(config) { - if (config != null) { - this.set(config); - } - } - - var keys; - - if (Object.keys) { - keys = Object.keys; - } else { - keys = function (obj) { - var i, res = []; - for (i in obj) { - if (hasOwnProp(obj, i)) { - res.push(i); - } - } - return res; - }; - } - - var defaultCalendar = { - sameDay: '[Today at] LT', - nextDay: '[Tomorrow at] LT', - nextWeek: 'dddd [at] LT', - lastDay: '[Yesterday at] LT', - lastWeek: '[Last] dddd [at] LT', - sameElse: 'L' - }; - - function calendar(key, mom, now) { - var output = this._calendar[key] || this._calendar['sameElse']; - return isFunction(output) ? output.call(mom, now) : output; - } - - var defaultLongDateFormat = { - LTS: 'h:mm:ss A', - LT: 'h:mm A', - L: 'MM/DD/YYYY', - LL: 'MMMM D, YYYY', - LLL: 'MMMM D, YYYY h:mm A', - LLLL: 'dddd, MMMM D, YYYY h:mm A' - }; - - function longDateFormat(key) { - var format = this._longDateFormat[key], - formatUpper = this._longDateFormat[key.toUpperCase()]; - - if (format || !formatUpper) { - return format; - } - - this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - - return this._longDateFormat[key]; - } - - var defaultInvalidDate = 'Invalid date'; - - function invalidDate() { - return this._invalidDate; - } - - var defaultOrdinal = '%d'; - var defaultDayOfMonthOrdinalParse = /\d{1,2}/; - - function ordinal(number) { - return this._ordinal.replace('%d', number); - } - - var defaultRelativeTime = { - future: 'in %s', - past: '%s ago', - s: 'a few seconds', - ss: '%d seconds', - m: 'a minute', - mm: '%d minutes', - h: 'an hour', - hh: '%d hours', - d: 'a day', - dd: '%d days', - M: 'a month', - MM: '%d months', - y: 'a year', - yy: '%d years' - }; - - function relativeTime(number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (isFunction(output)) ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - } - - function pastFuture(diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return isFunction(format) ? format(output) : format.replace(/%s/i, output); - } - - var aliases = {}; - - function addUnitAlias(unit, shorthand) { - var lowerCase = unit.toLowerCase(); - aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; - } - - function normalizeUnits(units) { - return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined; - } - - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - - return normalizedInput; - } - - var priorities = {}; - - function addUnitPriority(unit, priority) { - priorities[unit] = priority; - } - - function getPrioritizedUnits(unitsObj) { - var units = []; - for (var u in unitsObj) { - units.push({ unit: u, priority: priorities[u] }); - } - units.sort(function (a, b) { - return a.priority - b.priority; - }); - return units; - } - - function zeroFill(number, targetLength, forceSign) { - var absNumber = '' + Math.abs(number), - zerosToFill = targetLength - absNumber.length, - sign = number >= 0; - return (sign ? (forceSign ? '+' : '') : '-') + - Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber; - } - - var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g; - - var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; - - var formatFunctions = {}; - - var formatTokenFunctions = {}; - - // token: 'M' - // padded: ['MM', 2] - // ordinal: 'Mo' - // callback: function () { this.month() + 1 } - function addFormatToken(token, padded, ordinal, callback) { - var func = callback; - if (typeof callback === 'string') { - func = function () { - return this[callback](); - }; - } - if (token) { - formatTokenFunctions[token] = func; - } - if (padded) { - formatTokenFunctions[padded[0]] = function () { - return zeroFill(func.apply(this, arguments), padded[1], padded[2]); - }; - } - if (ordinal) { - formatTokenFunctions[ordinal] = function () { - return this.localeData().ordinal(func.apply(this, arguments), token); - }; - } - } - - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = '', i; - for (i = 0; i < length; i++) { - output += isFunction(array[i]) ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - - format = expandFormat(format, m.localeData()); - formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); - - return formatFunctions[format](m); - } - - function expandFormat(format, locale) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } - - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - - return format; - } - - var match1 = /\d/; // 0 - 9 - var match2 = /\d\d/; // 00 - 99 - var match3 = /\d{3}/; // 000 - 999 - var match4 = /\d{4}/; // 0000 - 9999 - var match6 = /[+-]?\d{6}/; // -999999 - 999999 - var match1to2 = /\d\d?/; // 0 - 99 - var match3to4 = /\d\d\d\d?/; // 999 - 9999 - var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999 - var match1to3 = /\d{1,3}/; // 0 - 999 - var match1to4 = /\d{1,4}/; // 0 - 9999 - var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999 - - var matchUnsigned = /\d+/; // 0 - inf - var matchSigned = /[+-]?\d+/; // -inf - inf - - var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z - var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z - - var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123 - - // any word (or two) characters or numbers including two/three word month in arabic. - // includes scottish gaelic two word and hyphenated months - var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i; - - - var regexes = {}; - - function addRegexToken(token, regex, strictRegex) { - regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) { - return (isStrict && strictRegex) ? strictRegex : regex; - }; - } - - function getParseRegexForToken(token, config) { - if (!hasOwnProp(regexes, token)) { - return new RegExp(unescapeFormat(token)); - } - - return regexes[token](config._strict, config._locale); - } - - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function unescapeFormat(s) { - return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - })); - } - - function regexEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - var tokens = {}; - - function addParseToken(token, callback) { - var i, func = callback; - if (typeof token === 'string') { - token = [token]; - } - if (isNumber(callback)) { - func = function (input, array) { - array[callback] = toInt(input); - }; - } - for (i = 0; i < token.length; i++) { - tokens[token[i]] = func; - } - } - - function addWeekParseToken(token, callback) { - addParseToken(token, function (input, array, config, token) { - config._w = config._w || {}; - callback(input, config._w, config, token); - }); - } - - function addTimeToArrayFromToken(token, input, config) { - if (input != null && hasOwnProp(tokens, token)) { - tokens[token](input, config._a, config, token); - } - } - - var YEAR = 0; - var MONTH = 1; - var DATE = 2; - var HOUR = 3; - var MINUTE = 4; - var SECOND = 5; - var MILLISECOND = 6; - var WEEK = 7; - var WEEKDAY = 8; - - // FORMATTING - - addFormatToken('Y', 0, 0, function () { - var y = this.year(); - return y <= 9999 ? '' + y : '+' + y; - }); - - addFormatToken(0, ['YY', 2], 0, function () { - return this.year() % 100; - }); - - addFormatToken(0, ['YYYY', 4], 0, 'year'); - addFormatToken(0, ['YYYYY', 5], 0, 'year'); - addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); - - // ALIASES - - addUnitAlias('year', 'y'); - - // PRIORITIES - - addUnitPriority('year', 1); - - // PARSING - - addRegexToken('Y', matchSigned); - addRegexToken('YY', match1to2, match2); - addRegexToken('YYYY', match1to4, match4); - addRegexToken('YYYYY', match1to6, match6); - addRegexToken('YYYYYY', match1to6, match6); - - addParseToken(['YYYYY', 'YYYYYY'], YEAR); - addParseToken('YYYY', function (input, array) { - array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); - }); - addParseToken('YY', function (input, array) { - array[YEAR] = hooks.parseTwoDigitYear(input); - }); - addParseToken('Y', function (input, array) { - array[YEAR] = parseInt(input, 10); - }); - - // HELPERS - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - // HOOKS - - hooks.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; - - // MOMENTS - - var getSetYear = makeGetSet('FullYear', true); - - function getIsLeapYear() { - return isLeapYear(this.year()); - } - - function makeGetSet(unit, keepTime) { - return function (value) { - if (value != null) { - set$1(this, unit, value); - hooks.updateOffset(this, keepTime); - return this; - } else { - return get(this, unit); - } - }; - } - - function get(mom, unit) { - return mom.isValid() ? - mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN; - } - - function set$1(mom, unit, value) { - if (mom.isValid() && !isNaN(value)) { - if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) { - mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month())); - } - else { - mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } - } - - // MOMENTS - - function stringGet(units) { - units = normalizeUnits(units); - if (isFunction(this[units])) { - return this[units](); - } - return this; - } - - - function stringSet(units, value) { - if (typeof units === 'object') { - units = normalizeObjectUnits(units); - var prioritized = getPrioritizedUnits(units); - for (var i = 0; i < prioritized.length; i++) { - this[prioritized[i].unit](units[prioritized[i].unit]); - } - } else { - units = normalizeUnits(units); - if (isFunction(this[units])) { - return this[units](value); - } - } - return this; - } - - function mod(n, x) { - return ((n % x) + x) % x; - } - - var indexOf; - - if (Array.prototype.indexOf) { - indexOf = Array.prototype.indexOf; - } else { - indexOf = function (o) { - // I know - var i; - for (i = 0; i < this.length; ++i) { - if (this[i] === o) { - return i; - } - } - return -1; - }; - } - - function daysInMonth(year, month) { - if (isNaN(year) || isNaN(month)) { - return NaN; - } - var modMonth = mod(month, 12); - year += (month - modMonth) / 12; - return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2); - } - - // FORMATTING - - addFormatToken('M', ['MM', 2], 'Mo', function () { - return this.month() + 1; - }); - - addFormatToken('MMM', 0, 0, function (format) { - return this.localeData().monthsShort(this, format); - }); - - addFormatToken('MMMM', 0, 0, function (format) { - return this.localeData().months(this, format); - }); - - // ALIASES - - addUnitAlias('month', 'M'); - - // PRIORITY - - addUnitPriority('month', 8); - - // PARSING - - addRegexToken('M', match1to2); - addRegexToken('MM', match1to2, match2); - addRegexToken('MMM', function (isStrict, locale) { - return locale.monthsShortRegex(isStrict); - }); - addRegexToken('MMMM', function (isStrict, locale) { - return locale.monthsRegex(isStrict); - }); - - addParseToken(['M', 'MM'], function (input, array) { - array[MONTH] = toInt(input) - 1; - }); - - addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { - var month = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (month != null) { - array[MONTH] = month; - } else { - getParsingFlags(config).invalidMonth = input; - } - }); - - // LOCALES - - var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/; - var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); - function localeMonths(m, format) { - if (!m) { - return isArray(this._months) ? this._months : - this._months['standalone']; - } - return isArray(this._months) ? this._months[m.month()] : - this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()]; - } - - var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); - function localeMonthsShort(m, format) { - if (!m) { - return isArray(this._monthsShort) ? this._monthsShort : - this._monthsShort['standalone']; - } - return isArray(this._monthsShort) ? this._monthsShort[m.month()] : - this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()]; - } - - function handleStrictParse(monthName, format, strict) { - var i, ii, mom, llc = monthName.toLocaleLowerCase(); - if (!this._monthsParse) { - // this is not used - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - for (i = 0; i < 12; ++i) { - mom = createUTC([2000, i]); - this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase(); - this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); - } - } - - if (strict) { - if (format === 'MMM') { - ii = indexOf.call(this._shortMonthsParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._longMonthsParse, llc); - return ii !== -1 ? ii : null; - } - } else { - if (format === 'MMM') { - ii = indexOf.call(this._shortMonthsParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._longMonthsParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._longMonthsParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._shortMonthsParse, llc); - return ii !== -1 ? ii : null; - } - } - } - - function localeMonthsParse(monthName, format, strict) { - var i, mom, regex; - - if (this._monthsParseExact) { - return handleStrictParse.call(this, monthName, format, strict); - } - - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } - - // TODO: add sorting - // Sorting makes sure if one month (or abbr) is a prefix of another - // see sorting in computeMonthsParse - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = createUTC([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); - } - if (!strict && !this._monthsParse[i]) { - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { - return i; - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } - } - - // MOMENTS - - function setMonth(mom, value) { - var dayOfMonth; - - if (!mom.isValid()) { - // No op - return mom; - } - - if (typeof value === 'string') { - if (/^\d+$/.test(value)) { - value = toInt(value); - } else { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (!isNumber(value)) { - return mom; - } - } - } - - dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } - - function getSetMonth(value) { - if (value != null) { - setMonth(this, value); - hooks.updateOffset(this, true); - return this; - } else { - return get(this, 'Month'); - } - } - - function getDaysInMonth() { - return daysInMonth(this.year(), this.month()); - } - - var defaultMonthsShortRegex = matchWord; - function monthsShortRegex(isStrict) { - if (this._monthsParseExact) { - if (!hasOwnProp(this, '_monthsRegex')) { - computeMonthsParse.call(this); - } - if (isStrict) { - return this._monthsShortStrictRegex; - } else { - return this._monthsShortRegex; - } - } else { - if (!hasOwnProp(this, '_monthsShortRegex')) { - this._monthsShortRegex = defaultMonthsShortRegex; - } - return this._monthsShortStrictRegex && isStrict ? - this._monthsShortStrictRegex : this._monthsShortRegex; - } - } - - var defaultMonthsRegex = matchWord; - function monthsRegex(isStrict) { - if (this._monthsParseExact) { - if (!hasOwnProp(this, '_monthsRegex')) { - computeMonthsParse.call(this); - } - if (isStrict) { - return this._monthsStrictRegex; - } else { - return this._monthsRegex; - } - } else { - if (!hasOwnProp(this, '_monthsRegex')) { - this._monthsRegex = defaultMonthsRegex; - } - return this._monthsStrictRegex && isStrict ? - this._monthsStrictRegex : this._monthsRegex; - } - } - - function computeMonthsParse() { - function cmpLenRev(a, b) { - return b.length - a.length; - } - - var shortPieces = [], longPieces = [], mixedPieces = [], - i, mom; - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = createUTC([2000, i]); - shortPieces.push(this.monthsShort(mom, '')); - longPieces.push(this.months(mom, '')); - mixedPieces.push(this.months(mom, '')); - mixedPieces.push(this.monthsShort(mom, '')); - } - // Sorting makes sure if one month (or abbr) is a prefix of another it - // will match the longer piece. - shortPieces.sort(cmpLenRev); - longPieces.sort(cmpLenRev); - mixedPieces.sort(cmpLenRev); - for (i = 0; i < 12; i++) { - shortPieces[i] = regexEscape(shortPieces[i]); - longPieces[i] = regexEscape(longPieces[i]); - } - for (i = 0; i < 24; i++) { - mixedPieces[i] = regexEscape(mixedPieces[i]); - } - - this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); - this._monthsShortRegex = this._monthsRegex; - this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i'); - this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i'); - } - - function createDate(y, m, d, h, M, s, ms) { - // can't just apply() to create a date: - // https://stackoverflow.com/q/181348 - var date = new Date(y, m, d, h, M, s, ms); - - // the date constructor remaps years 0-99 to 1900-1999 - if (y < 100 && y >= 0 && isFinite(date.getFullYear())) { - date.setFullYear(y); - } - return date; - } - - function createUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - - // the Date.UTC function remaps years 0-99 to 1900-1999 - if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) { - date.setUTCFullYear(y); - } - return date; - } - - // start-of-first-week - start-of-year - function firstWeekOffset(year, dow, doy) { - var // first-week day -- which january is always in the first week (4 for iso, 1 for other) - fwd = 7 + dow - doy, - // first-week day local weekday -- which local weekday is fwd - fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; - - return -fwdlw + fwd - 1; - } - - // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, dow, doy) { - var localWeekday = (7 + weekday - dow) % 7, - weekOffset = firstWeekOffset(year, dow, doy), - dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, - resYear, resDayOfYear; - - if (dayOfYear <= 0) { - resYear = year - 1; - resDayOfYear = daysInYear(resYear) + dayOfYear; - } else if (dayOfYear > daysInYear(year)) { - resYear = year + 1; - resDayOfYear = dayOfYear - daysInYear(year); - } else { - resYear = year; - resDayOfYear = dayOfYear; - } - - return { - year: resYear, - dayOfYear: resDayOfYear - }; - } - - function weekOfYear(mom, dow, doy) { - var weekOffset = firstWeekOffset(mom.year(), dow, doy), - week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, - resWeek, resYear; - - if (week < 1) { - resYear = mom.year() - 1; - resWeek = week + weeksInYear(resYear, dow, doy); - } else if (week > weeksInYear(mom.year(), dow, doy)) { - resWeek = week - weeksInYear(mom.year(), dow, doy); - resYear = mom.year() + 1; - } else { - resYear = mom.year(); - resWeek = week; - } - - return { - week: resWeek, - year: resYear - }; - } - - function weeksInYear(year, dow, doy) { - var weekOffset = firstWeekOffset(year, dow, doy), - weekOffsetNext = firstWeekOffset(year + 1, dow, doy); - return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; - } - - // FORMATTING - - addFormatToken('w', ['ww', 2], 'wo', 'week'); - addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); - - // ALIASES - - addUnitAlias('week', 'w'); - addUnitAlias('isoWeek', 'W'); - - // PRIORITIES - - addUnitPriority('week', 5); - addUnitPriority('isoWeek', 5); - - // PARSING - - addRegexToken('w', match1to2); - addRegexToken('ww', match1to2, match2); - addRegexToken('W', match1to2); - addRegexToken('WW', match1to2, match2); - - addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) { - week[token.substr(0, 1)] = toInt(input); - }); - - // HELPERS - - // LOCALES - - function localeWeek(mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - } - - var defaultLocaleWeek = { - dow: 0, // Sunday is the first day of the week. - doy: 6 // The week that contains Jan 1st is the first week of the year. - }; - - function localeFirstDayOfWeek() { - return this._week.dow; - } - - function localeFirstDayOfYear() { - return this._week.doy; - } - - // MOMENTS - - function getSetWeek(input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - } - - function getSetISOWeek(input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - } - - // FORMATTING - - addFormatToken('d', 0, 'do', 'day'); - - addFormatToken('dd', 0, 0, function (format) { - return this.localeData().weekdaysMin(this, format); - }); - - addFormatToken('ddd', 0, 0, function (format) { - return this.localeData().weekdaysShort(this, format); - }); - - addFormatToken('dddd', 0, 0, function (format) { - return this.localeData().weekdays(this, format); - }); - - addFormatToken('e', 0, 0, 'weekday'); - addFormatToken('E', 0, 0, 'isoWeekday'); - - // ALIASES - - addUnitAlias('day', 'd'); - addUnitAlias('weekday', 'e'); - addUnitAlias('isoWeekday', 'E'); - - // PRIORITY - addUnitPriority('day', 11); - addUnitPriority('weekday', 11); - addUnitPriority('isoWeekday', 11); - - // PARSING - - addRegexToken('d', match1to2); - addRegexToken('e', match1to2); - addRegexToken('E', match1to2); - addRegexToken('dd', function (isStrict, locale) { - return locale.weekdaysMinRegex(isStrict); - }); - addRegexToken('ddd', function (isStrict, locale) { - return locale.weekdaysShortRegex(isStrict); - }); - addRegexToken('dddd', function (isStrict, locale) { - return locale.weekdaysRegex(isStrict); - }); - - addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { - var weekday = config._locale.weekdaysParse(input, token, config._strict); - // if we didn't get a weekday name, mark the date as invalid - if (weekday != null) { - week.d = weekday; - } else { - getParsingFlags(config).invalidWeekday = input; - } - }); - - addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { - week[token] = toInt(input); - }); - - // HELPERS - - function parseWeekday(input, locale) { - if (typeof input !== 'string') { - return input; - } - - if (!isNaN(input)) { - return parseInt(input, 10); - } - - input = locale.weekdaysParse(input); - if (typeof input === 'number') { - return input; - } - - return null; - } - - function parseIsoWeekday(input, locale) { - if (typeof input === 'string') { - return locale.weekdaysParse(input) % 7 || 7; - } - return isNaN(input) ? null : input; - } - - // LOCALES - - var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); - function localeWeekdays(m, format) { - if (!m) { - return isArray(this._weekdays) ? this._weekdays : - this._weekdays['standalone']; - } - return isArray(this._weekdays) ? this._weekdays[m.day()] : - this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()]; - } - - var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); - function localeWeekdaysShort(m) { - return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort; - } - - var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); - function localeWeekdaysMin(m) { - return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin; - } - - function handleStrictParse$1(weekdayName, format, strict) { - var i, ii, mom, llc = weekdayName.toLocaleLowerCase(); - if (!this._weekdaysParse) { - this._weekdaysParse = []; - this._shortWeekdaysParse = []; - this._minWeekdaysParse = []; - - for (i = 0; i < 7; ++i) { - mom = createUTC([2000, 1]).day(i); - this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase(); - this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase(); - this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); - } - } - - if (strict) { - if (format === 'dddd') { - ii = indexOf.call(this._weekdaysParse, llc); - return ii !== -1 ? ii : null; - } else if (format === 'ddd') { - ii = indexOf.call(this._shortWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._minWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } - } else { - if (format === 'dddd') { - ii = indexOf.call(this._weekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._shortWeekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._minWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } else if (format === 'ddd') { - ii = indexOf.call(this._shortWeekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._weekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._minWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._minWeekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._weekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._shortWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } - } - } - - function localeWeekdaysParse(weekdayName, format, strict) { - var i, mom, regex; - - if (this._weekdaysParseExact) { - return handleStrictParse$1.call(this, weekdayName, format, strict); - } - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - this._minWeekdaysParse = []; - this._shortWeekdaysParse = []; - this._fullWeekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - - mom = createUTC([2000, 1]).day(i); - if (strict && !this._fullWeekdaysParse[i]) { - this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i'); - this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i'); - this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i'); - } - if (!this._weekdaysParse[i]) { - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) { - return i; - } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) { - return i; - } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) { - return i; - } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - } - - // MOMENTS - - function getSetDayOfWeek(input) { - if (!this.isValid()) { - return input != null ? this : NaN; - } - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - } - - function getSetLocaleDayOfWeek(input) { - if (!this.isValid()) { - return input != null ? this : NaN; - } - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - } - - function getSetISODayOfWeek(input) { - if (!this.isValid()) { - return input != null ? this : NaN; - } - - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - - if (input != null) { - var weekday = parseIsoWeekday(input, this.localeData()); - return this.day(this.day() % 7 ? weekday : weekday - 7); - } else { - return this.day() || 7; - } - } - - var defaultWeekdaysRegex = matchWord; - function weekdaysRegex(isStrict) { - if (this._weekdaysParseExact) { - if (!hasOwnProp(this, '_weekdaysRegex')) { - computeWeekdaysParse.call(this); - } - if (isStrict) { - return this._weekdaysStrictRegex; - } else { - return this._weekdaysRegex; - } - } else { - if (!hasOwnProp(this, '_weekdaysRegex')) { - this._weekdaysRegex = defaultWeekdaysRegex; - } - return this._weekdaysStrictRegex && isStrict ? - this._weekdaysStrictRegex : this._weekdaysRegex; - } - } - - var defaultWeekdaysShortRegex = matchWord; - function weekdaysShortRegex(isStrict) { - if (this._weekdaysParseExact) { - if (!hasOwnProp(this, '_weekdaysRegex')) { - computeWeekdaysParse.call(this); - } - if (isStrict) { - return this._weekdaysShortStrictRegex; - } else { - return this._weekdaysShortRegex; - } - } else { - if (!hasOwnProp(this, '_weekdaysShortRegex')) { - this._weekdaysShortRegex = defaultWeekdaysShortRegex; - } - return this._weekdaysShortStrictRegex && isStrict ? - this._weekdaysShortStrictRegex : this._weekdaysShortRegex; - } - } - - var defaultWeekdaysMinRegex = matchWord; - function weekdaysMinRegex(isStrict) { - if (this._weekdaysParseExact) { - if (!hasOwnProp(this, '_weekdaysRegex')) { - computeWeekdaysParse.call(this); - } - if (isStrict) { - return this._weekdaysMinStrictRegex; - } else { - return this._weekdaysMinRegex; - } - } else { - if (!hasOwnProp(this, '_weekdaysMinRegex')) { - this._weekdaysMinRegex = defaultWeekdaysMinRegex; - } - return this._weekdaysMinStrictRegex && isStrict ? - this._weekdaysMinStrictRegex : this._weekdaysMinRegex; - } - } - - - function computeWeekdaysParse() { - function cmpLenRev(a, b) { - return b.length - a.length; - } - - var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [], - i, mom, minp, shortp, longp; - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - mom = createUTC([2000, 1]).day(i); - minp = this.weekdaysMin(mom, ''); - shortp = this.weekdaysShort(mom, ''); - longp = this.weekdays(mom, ''); - minPieces.push(minp); - shortPieces.push(shortp); - longPieces.push(longp); - mixedPieces.push(minp); - mixedPieces.push(shortp); - mixedPieces.push(longp); - } - // Sorting makes sure if one weekday (or abbr) is a prefix of another it - // will match the longer piece. - minPieces.sort(cmpLenRev); - shortPieces.sort(cmpLenRev); - longPieces.sort(cmpLenRev); - mixedPieces.sort(cmpLenRev); - for (i = 0; i < 7; i++) { - shortPieces[i] = regexEscape(shortPieces[i]); - longPieces[i] = regexEscape(longPieces[i]); - mixedPieces[i] = regexEscape(mixedPieces[i]); - } - - this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); - this._weekdaysShortRegex = this._weekdaysRegex; - this._weekdaysMinRegex = this._weekdaysRegex; - - this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i'); - this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i'); - this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i'); - } - - // FORMATTING - - function hFormat() { - return this.hours() % 12 || 12; - } - - function kFormat() { - return this.hours() || 24; - } - - addFormatToken('H', ['HH', 2], 0, 'hour'); - addFormatToken('h', ['hh', 2], 0, hFormat); - addFormatToken('k', ['kk', 2], 0, kFormat); - - addFormatToken('hmm', 0, 0, function () { - return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); - }); - - addFormatToken('hmmss', 0, 0, function () { - return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + - zeroFill(this.seconds(), 2); - }); - - addFormatToken('Hmm', 0, 0, function () { - return '' + this.hours() + zeroFill(this.minutes(), 2); - }); - - addFormatToken('Hmmss', 0, 0, function () { - return '' + this.hours() + zeroFill(this.minutes(), 2) + - zeroFill(this.seconds(), 2); - }); - - function meridiem(token, lowercase) { - addFormatToken(token, 0, 0, function () { - return this.localeData().meridiem(this.hours(), this.minutes(), lowercase); - }); - } - - meridiem('a', true); - meridiem('A', false); - - // ALIASES - - addUnitAlias('hour', 'h'); - - // PRIORITY - addUnitPriority('hour', 13); - - // PARSING - - function matchMeridiem(isStrict, locale) { - return locale._meridiemParse; - } - - addRegexToken('a', matchMeridiem); - addRegexToken('A', matchMeridiem); - addRegexToken('H', match1to2); - addRegexToken('h', match1to2); - addRegexToken('k', match1to2); - addRegexToken('HH', match1to2, match2); - addRegexToken('hh', match1to2, match2); - addRegexToken('kk', match1to2, match2); - - addRegexToken('hmm', match3to4); - addRegexToken('hmmss', match5to6); - addRegexToken('Hmm', match3to4); - addRegexToken('Hmmss', match5to6); - - addParseToken(['H', 'HH'], HOUR); - addParseToken(['k', 'kk'], function (input, array, config) { - var kInput = toInt(input); - array[HOUR] = kInput === 24 ? 0 : kInput; - }); - addParseToken(['a', 'A'], function (input, array, config) { - config._isPm = config._locale.isPM(input); - config._meridiem = input; - }); - addParseToken(['h', 'hh'], function (input, array, config) { - array[HOUR] = toInt(input); - getParsingFlags(config).bigHour = true; - }); - addParseToken('hmm', function (input, array, config) { - var pos = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos)); - array[MINUTE] = toInt(input.substr(pos)); - getParsingFlags(config).bigHour = true; - }); - addParseToken('hmmss', function (input, array, config) { - var pos1 = input.length - 4; - var pos2 = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos1)); - array[MINUTE] = toInt(input.substr(pos1, 2)); - array[SECOND] = toInt(input.substr(pos2)); - getParsingFlags(config).bigHour = true; - }); - addParseToken('Hmm', function (input, array, config) { - var pos = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos)); - array[MINUTE] = toInt(input.substr(pos)); - }); - addParseToken('Hmmss', function (input, array, config) { - var pos1 = input.length - 4; - var pos2 = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos1)); - array[MINUTE] = toInt(input.substr(pos1, 2)); - array[SECOND] = toInt(input.substr(pos2)); - }); - - // LOCALES - - function localeIsPM(input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - } - - var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i; - function localeMeridiem(hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - } - - - // MOMENTS - - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - var getSetHour = makeGetSet('Hours', true); - - // months - // week - // weekdays - // meridiem - var baseConfig = { - calendar: defaultCalendar, - longDateFormat: defaultLongDateFormat, - invalidDate: defaultInvalidDate, - ordinal: defaultOrdinal, - dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, - relativeTime: defaultRelativeTime, - - months: defaultLocaleMonths, - monthsShort: defaultLocaleMonthsShort, - - week: defaultLocaleWeek, - - weekdays: defaultLocaleWeekdays, - weekdaysMin: defaultLocaleWeekdaysMin, - weekdaysShort: defaultLocaleWeekdaysShort, - - meridiemParse: defaultLocaleMeridiemParse - }; - - // internal storage for locale config files - var locales = {}; - var localeFamilies = {}; - var globalLocale; - - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // pick the locale from the array - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { - var i = 0, j, next, locale, split; - - while (i < names.length) { - split = normalizeLocale(names[i]).split('-'); - j = split.length; - next = normalizeLocale(names[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - locale = loadLocale(split.slice(0, j).join('-')); - if (locale) { - return locale; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return null; - } - - function loadLocale(name) { - var oldLocale = null; - // TODO: Find a better way to register and load all the locales in Node - if (!locales[name] && (typeof module !== 'undefined') && - module && module.exports) { - try { - oldLocale = globalLocale._abbr; - var aliasedRequire = require; - aliasedRequire('./locale/' + name); - getSetGlobalLocale(oldLocale); - } catch (e) { } - } - return locales[name]; - } - - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - function getSetGlobalLocale(key, values) { - var data; - if (key) { - if (isUndefined(values)) { - data = getLocale(key); - } - else { - data = defineLocale(key, values); - } - - if (data) { - // moment.duration._locale = moment._locale = data; - globalLocale = data; - } - } - - return globalLocale._abbr; - } - - function defineLocale(name, config) { - if (config !== null) { - var parentConfig = baseConfig; - config.abbr = name; - if (locales[name] != null) { - deprecateSimple('defineLocaleOverride', - 'use moment.updateLocale(localeName, config) to change ' + - 'an existing locale. moment.defineLocale(localeName, ' + - 'config) should only be used for creating a new locale ' + - 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.'); - parentConfig = locales[name]._config; - } else if (config.parentLocale != null) { - if (locales[config.parentLocale] != null) { - parentConfig = locales[config.parentLocale]._config; - } else { - if (!localeFamilies[config.parentLocale]) { - localeFamilies[config.parentLocale] = []; - } - localeFamilies[config.parentLocale].push({ - name: name, - config: config - }); - return null; - } - } - locales[name] = new Locale(mergeConfigs(parentConfig, config)); - - if (localeFamilies[name]) { - localeFamilies[name].forEach(function (x) { - defineLocale(x.name, x.config); - }); - } - - // backwards compat for now: also set the locale - // make sure we set the locale AFTER all child locales have been - // created, so we won't end up with the child locale set. - getSetGlobalLocale(name); - - - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - } - - function updateLocale(name, config) { - if (config != null) { - var locale, tmpLocale, parentConfig = baseConfig; - // MERGE - tmpLocale = loadLocale(name); - if (tmpLocale != null) { - parentConfig = tmpLocale._config; - } - config = mergeConfigs(parentConfig, config); - locale = new Locale(config); - locale.parentLocale = locales[name]; - locales[name] = locale; - - // backwards compat for now: also set the locale - getSetGlobalLocale(name); - } else { - // pass null for config to unupdate, useful for tests - if (locales[name] != null) { - if (locales[name].parentLocale != null) { - locales[name] = locales[name].parentLocale; - } else if (locales[name] != null) { - delete locales[name]; - } - } - } - return locales[name]; - } - - // returns locale data - function getLocale(key) { - var locale; - - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } - - if (!key) { - return globalLocale; - } - - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - - return chooseLocale(key); - } - - function listLocales() { - return keys(locales); - } - - function checkOverflow(m) { - var overflow; - var a = m._a; - - if (a && getParsingFlags(m).overflow === -2) { - overflow = - a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : - a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : - a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR : - a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : - a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : - a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - if (getParsingFlags(m)._overflowWeeks && overflow === -1) { - overflow = WEEK; - } - if (getParsingFlags(m)._overflowWeekday && overflow === -1) { - overflow = WEEKDAY; - } - - getParsingFlags(m).overflow = overflow; - } - - return m; - } - - // Pick the first defined of two or three arguments. - function defaults(a, b, c) { - if (a != null) { - return a; - } - if (b != null) { - return b; - } - return c; - } - - function currentDateArray(config) { - // hooks is actually the exported moment object - var nowValue = new Date(hooks.now()); - if (config._useUTC) { - return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()]; - } - return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function configFromArray(config) { - var i, date, input = [], currentDate, expectedWeekday, yearToUse; - - if (config._d) { - return; - } - - currentDate = currentDateArray(config); - - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } - - //if the day of the year is set, figure out what it is - if (config._dayOfYear != null) { - yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); - - if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) { - getParsingFlags(config)._overflowDayOfYear = true; - } - - date = createUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - // Check for 24:00:00.000 - if (config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0) { - config._nextDay = true; - config._a[HOUR] = 0; - } - - config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input); - expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay(); - - // Apply timezone offset from input. The actual utcOffset can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); - } - - if (config._nextDay) { - config._a[HOUR] = 24; - } - - // check for mismatching day of week - if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) { - getParsingFlags(config).weekdayMismatch = true; - } - } - - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; - - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year); - week = defaults(w.W, 1); - weekday = defaults(w.E, 1); - if (weekday < 1 || weekday > 7) { - weekdayOverflow = true; - } - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; - - var curWeek = weekOfYear(createLocal(), dow, doy); - - weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); - - // Default to current week. - week = defaults(w.w, curWeek.week); - - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < 0 || weekday > 6) { - weekdayOverflow = true; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - if (w.e < 0 || w.e > 6) { - weekdayOverflow = true; - } - } else { - // default to begining of week - weekday = dow; - } - } - if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { - getParsingFlags(config)._overflowWeeks = true; - } else if (weekdayOverflow != null) { - getParsingFlags(config)._overflowWeekday = true; - } else { - temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - } - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/; - var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/; - - var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/; - - var isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], - ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], - ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], - ['GGGG-[W]WW', /\d{4}-W\d\d/, false], - ['YYYY-DDD', /\d{4}-\d{3}/], - ['YYYY-MM', /\d{4}-\d\d/, false], - ['YYYYYYMMDD', /[+-]\d{10}/], - ['YYYYMMDD', /\d{8}/], - // YYYYMM is NOT allowed by the standard - ['GGGG[W]WWE', /\d{4}W\d{3}/], - ['GGGG[W]WW', /\d{4}W\d{2}/, false], - ['YYYYDDD', /\d{7}/] - ]; - - // iso time formats and regexes - var isoTimes = [ - ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], - ['HH:mm:ss', /\d\d:\d\d:\d\d/], - ['HH:mm', /\d\d:\d\d/], - ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], - ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], - ['HHmmss', /\d\d\d\d\d\d/], - ['HHmm', /\d\d\d\d/], - ['HH', /\d\d/] - ]; - - var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; - - // date from iso format - function configFromISO(config) { - var i, l, - string = config._i, - match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), - allowTime, dateFormat, timeFormat, tzFormat; - - if (match) { - getParsingFlags(config).iso = true; - - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(match[1])) { - dateFormat = isoDates[i][0]; - allowTime = isoDates[i][2] !== false; - break; - } - } - if (dateFormat == null) { - config._isValid = false; - return; - } - if (match[3]) { - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(match[3])) { - // match[2] should be 'T' or space - timeFormat = (match[2] || ' ') + isoTimes[i][0]; - break; - } - } - if (timeFormat == null) { - config._isValid = false; - return; - } - } - if (!allowTime && timeFormat != null) { - config._isValid = false; - return; - } - if (match[4]) { - if (tzRegex.exec(match[4])) { - tzFormat = 'Z'; - } else { - config._isValid = false; - return; - } - } - config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); - configFromStringAndFormat(config); - } else { - config._isValid = false; - } - } - - // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 - var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/; - - function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) { - var result = [ - untruncateYear(yearStr), - defaultLocaleMonthsShort.indexOf(monthStr), - parseInt(dayStr, 10), - parseInt(hourStr, 10), - parseInt(minuteStr, 10) - ]; - - if (secondStr) { - result.push(parseInt(secondStr, 10)); - } - - return result; - } - - function untruncateYear(yearStr) { - var year = parseInt(yearStr, 10); - if (year <= 49) { - return 2000 + year; - } else if (year <= 999) { - return 1900 + year; - } - return year; - } - - function preprocessRFC2822(s) { - // Remove comments and folding whitespace and replace multiple-spaces with a single space - return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim(); - } - - function checkWeekday(weekdayStr, parsedInput, config) { - if (weekdayStr) { - // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check. - var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), - weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay(); - if (weekdayProvided !== weekdayActual) { - getParsingFlags(config).weekdayMismatch = true; - config._isValid = false; - return false; - } - } - return true; - } - - var obsOffsets = { - UT: 0, - GMT: 0, - EDT: -4 * 60, - EST: -5 * 60, - CDT: -5 * 60, - CST: -6 * 60, - MDT: -6 * 60, - MST: -7 * 60, - PDT: -7 * 60, - PST: -8 * 60 - }; - - function calculateOffset(obsOffset, militaryOffset, numOffset) { - if (obsOffset) { - return obsOffsets[obsOffset]; - } else if (militaryOffset) { - // the only allowed military tz is Z - return 0; - } else { - var hm = parseInt(numOffset, 10); - var m = hm % 100, h = (hm - m) / 100; - return h * 60 + m; - } - } - - // date and time from ref 2822 format - function configFromRFC2822(config) { - var match = rfc2822.exec(preprocessRFC2822(config._i)); - if (match) { - var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]); - if (!checkWeekday(match[1], parsedArray, config)) { - return; - } - - config._a = parsedArray; - config._tzm = calculateOffset(match[8], match[9], match[10]); - - config._d = createUTCDate.apply(null, config._a); - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); - - getParsingFlags(config).rfc2822 = true; - } else { - config._isValid = false; - } - } - - // date from iso format or fallback - function configFromString(config) { - var matched = aspNetJsonRegex.exec(config._i); - - if (matched !== null) { - config._d = new Date(+matched[1]); - return; - } - - configFromISO(config); - if (config._isValid === false) { - delete config._isValid; - } else { - return; - } - - configFromRFC2822(config); - if (config._isValid === false) { - delete config._isValid; - } else { - return; - } - - // Final attempt, use Input Fallback - hooks.createFromInputFallback(config); - } - - hooks.createFromInputFallback = deprecate( - 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + - 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + - 'discouraged and will be removed in an upcoming major release. Please refer to ' + - 'http://momentjs.com/guides/#/warnings/js-date/ for more info.', - function (config) { - config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); - } - ); - - // constant that refers to the ISO standard - hooks.ISO_8601 = function () { }; - - // constant that refers to the RFC 2822 form - hooks.RFC_2822 = function () { }; - - // date from string and format string - function configFromStringAndFormat(config) { - // TODO: Move this to another part of the creation flow to prevent circular deps - if (config._f === hooks.ISO_8601) { - configFromISO(config); - return; - } - if (config._f === hooks.RFC_2822) { - configFromRFC2822(config); - return; - } - config._a = []; - getParsingFlags(config).empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - // console.log('token', token, 'parsedInput', parsedInput, - // 'regex', getParseRegexForToken(token, config)); - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - getParsingFlags(config).unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - getParsingFlags(config).empty = false; - } - else { - getParsingFlags(config).unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - getParsingFlags(config).unusedTokens.push(token); - } - } - - // add remaining unparsed input length to the string - getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - getParsingFlags(config).unusedInput.push(string); - } - - // clear _12h flag if hour is <= 12 - if (config._a[HOUR] <= 12 && - getParsingFlags(config).bigHour === true && - config._a[HOUR] > 0) { - getParsingFlags(config).bigHour = undefined; - } - - getParsingFlags(config).parsedDateParts = config._a.slice(0); - getParsingFlags(config).meridiem = config._meridiem; - // handle meridiem - config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); - - configFromArray(config); - checkOverflow(config); - } - - - function meridiemFixWrap(locale, hour, meridiem) { - var isPm; - - if (meridiem == null) { - // nothing to do - return hour; - } - if (locale.meridiemHour != null) { - return locale.meridiemHour(hour, meridiem); - } else if (locale.isPM != null) { - // Fallback - isPm = locale.isPM(meridiem); - if (isPm && hour < 12) { - hour += 12; - } - if (!isPm && hour === 12) { - hour = 0; - } - return hour; - } else { - // this is not supposed to happen - return hour; - } - } - - // date from string and array of format strings - function configFromStringAndArray(config) { - var tempConfig, - bestMoment, - - scoreToBeat, - i, - currentScore; - - if (config._f.length === 0) { - getParsingFlags(config).invalidFormat = true; - config._d = new Date(NaN); - return; - } - - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._f = config._f[i]; - configFromStringAndFormat(tempConfig); - - if (!isValid(tempConfig)) { - continue; - } - - // if there is any input that was not parsed add a penalty for that format - currentScore += getParsingFlags(tempConfig).charsLeftOver; - - //or tokens - currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; - - getParsingFlags(tempConfig).score = currentScore; - - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - - extend(config, bestMoment || tempConfig); - } - - function configFromObject(config) { - if (config._d) { - return; - } - - var i = normalizeObjectUnits(config._i); - config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) { - return obj && parseInt(obj, 10); - }); - - configFromArray(config); - } - - function createFromConfig(config) { - var res = new Moment(checkOverflow(prepareConfig(config))); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } - - return res; - } - - function prepareConfig(config) { - var input = config._i, - format = config._f; - - config._locale = config._locale || getLocale(config._l); - - if (input === null || (format === undefined && input === '')) { - return createInvalid({ nullInput: true }); - } - - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } - - if (isMoment(input)) { - return new Moment(checkOverflow(input)); - } else if (isDate(input)) { - config._d = input; - } else if (isArray(format)) { - configFromStringAndArray(config); - } else if (format) { - configFromStringAndFormat(config); - } else { - configFromInput(config); - } - - if (!isValid(config)) { - config._d = null; - } - - return config; - } - - function configFromInput(config) { - var input = config._i; - if (isUndefined(input)) { - config._d = new Date(hooks.now()); - } else if (isDate(input)) { - config._d = new Date(input.valueOf()); - } else if (typeof input === 'string') { - configFromString(config); - } else if (isArray(input)) { - config._a = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - configFromArray(config); - } else if (isObject(input)) { - configFromObject(config); - } else if (isNumber(input)) { - // from milliseconds - config._d = new Date(input); - } else { - hooks.createFromInputFallback(config); - } - } - - function createLocalOrUTC(input, format, locale, strict, isUTC) { - var c = {}; - - if (locale === true || locale === false) { - strict = locale; - locale = undefined; - } - - if ((isObject(input) && isObjectEmpty(input)) || - (isArray(input) && input.length === 0)) { - input = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c._isAMomentObject = true; - c._useUTC = c._isUTC = isUTC; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - - return createFromConfig(c); - } - - function createLocal(input, format, locale, strict) { - return createLocalOrUTC(input, format, locale, strict, false); - } - - var prototypeMin = deprecate( - 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', - function () { - var other = createLocal.apply(null, arguments); - if (this.isValid() && other.isValid()) { - return other < this ? this : other; - } else { - return createInvalid(); - } - } - ); - - var prototypeMax = deprecate( - 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', - function () { - var other = createLocal.apply(null, arguments); - if (this.isValid() && other.isValid()) { - return other > this ? this : other; - } else { - return createInvalid(); - } - } - ); - - // Pick a moment m from moments so that m[fn](other) is true for all - // other. This relies on the function fn to be transitive. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return createLocal(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (!moments[i].isValid() || moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } - - // TODO: Use [].sort instead? - function min() { - var args = [].slice.call(arguments, 0); - - return pickBy('isBefore', args); - } - - function max() { - var args = [].slice.call(arguments, 0); - - return pickBy('isAfter', args); - } - - var now = function () { - return Date.now ? Date.now() : +(new Date()); - }; - - var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond']; - - function isDurationValid(m) { - for (var key in m) { - if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) { - return false; - } - } - - var unitHasDecimal = false; - for (var i = 0; i < ordering.length; ++i) { - if (m[ordering[i]]) { - if (unitHasDecimal) { - return false; // only allow non-integers for smallest unit - } - if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { - unitHasDecimal = true; - } - } - } - - return true; - } - - function isValid$1() { - return this._isValid; - } - - function createInvalid$1() { - return createDuration(NaN); - } - - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - this._isValid = isDurationValid(normalizedInput); - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible to translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - - this._data = {}; - - this._locale = getLocale(); - - this._bubble(); - } - - function isDuration(obj) { - return obj instanceof Duration; - } - - function absRound(number) { - if (number < 0) { - return Math.round(-1 * number) * -1; - } else { - return Math.round(number); - } - } - - // FORMATTING - - function offset(token, separator) { - addFormatToken(token, 0, 0, function () { - var offset = this.utcOffset(); - var sign = '+'; - if (offset < 0) { - offset = -offset; - sign = '-'; - } - return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2); - }); - } - - offset('Z', ':'); - offset('ZZ', ''); - - // PARSING - - addRegexToken('Z', matchShortOffset); - addRegexToken('ZZ', matchShortOffset); - addParseToken(['Z', 'ZZ'], function (input, array, config) { - config._useUTC = true; - config._tzm = offsetFromString(matchShortOffset, input); - }); - - // HELPERS - - // timezone chunker - // '+10:00' > ['10', '00'] - // '-1530' > ['-15', '30'] - var chunkOffset = /([\+\-]|\d\d)/gi; - - function offsetFromString(matcher, string) { - var matches = (string || '').match(matcher); - - if (matches === null) { - return null; - } - - var chunk = matches[matches.length - 1] || []; - var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; - var minutes = +(parts[1] * 60) + toInt(parts[2]); - - return minutes === 0 ? - 0 : - parts[0] === '+' ? minutes : -minutes; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function cloneWithOffset(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); - // Use low-level api, because this fn is low-level api. - res._d.setTime(res._d.valueOf() + diff); - hooks.updateOffset(res, false); - return res; - } else { - return createLocal(input).local(); - } - } - - function getDateOffset(m) { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return -Math.round(m._d.getTimezoneOffset() / 15) * 15; - } - - // HOOKS - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - hooks.updateOffset = function () { }; - - // MOMENTS - - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset - // +0200, so we adjust the time as needed, to be valid. - // - // Keeping the time actually adds/subtracts (one hour) - // from the actual represented time. That is why we call updateOffset - // a second time. In case it wants us to change the offset again - // _changeInProgress == true case, then we have to adjust, because - // there is no such time in the given timezone. - function getSetOffset(input, keepLocalTime, keepMinutes) { - var offset = this._offset || 0, - localAdjust; - if (!this.isValid()) { - return input != null ? this : NaN; - } - if (input != null) { - if (typeof input === 'string') { - input = offsetFromString(matchShortOffset, input); - if (input === null) { - return this; - } - } else if (Math.abs(input) < 16 && !keepMinutes) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = getDateOffset(this); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.add(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addSubtract(this, createDuration(input - offset, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - hooks.updateOffset(this, true); - this._changeInProgress = null; - } - } - return this; - } else { - return this._isUTC ? offset : getDateOffset(this); - } - } - - function getSetZone(input, keepLocalTime) { - if (input != null) { - if (typeof input !== 'string') { - input = -input; - } - - this.utcOffset(input, keepLocalTime); - - return this; - } else { - return -this.utcOffset(); - } - } - - function setOffsetToUTC(keepLocalTime) { - return this.utcOffset(0, keepLocalTime); - } - - function setOffsetToLocal(keepLocalTime) { - if (this._isUTC) { - this.utcOffset(0, keepLocalTime); - this._isUTC = false; - - if (keepLocalTime) { - this.subtract(getDateOffset(this), 'm'); - } - } - return this; - } - - function setOffsetToParsedOffset() { - if (this._tzm != null) { - this.utcOffset(this._tzm, false, true); - } else if (typeof this._i === 'string') { - var tZone = offsetFromString(matchOffset, this._i); - if (tZone != null) { - this.utcOffset(tZone); - } - else { - this.utcOffset(0, true); - } - } - return this; - } - - function hasAlignedHourOffset(input) { - if (!this.isValid()) { - return false; - } - input = input ? createLocal(input).utcOffset() : 0; - - return (this.utcOffset() - input) % 60 === 0; - } - - function isDaylightSavingTime() { - return ( - this.utcOffset() > this.clone().month(0).utcOffset() || - this.utcOffset() > this.clone().month(5).utcOffset() - ); - } - - function isDaylightSavingTimeShifted() { - if (!isUndefined(this._isDSTShifted)) { - return this._isDSTShifted; - } - - var c = {}; - - copyConfig(c, this); - c = prepareConfig(c); - - if (c._a) { - var other = c._isUTC ? createUTC(c._a) : createLocal(c._a); - this._isDSTShifted = this.isValid() && - compareArrays(c._a, other.toArray()) > 0; - } else { - this._isDSTShifted = false; - } - - return this._isDSTShifted; - } - - function isLocal() { - return this.isValid() ? !this._isUTC : false; - } - - function isUtcOffset() { - return this.isValid() ? this._isUTC : false; - } - - function isUtc() { - return this.isValid() ? this._isUTC && this._offset === 0 : false; - } - - // ASP.NET json date format regex - var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - // and further modified to allow for strings containing both week and day - var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; - - function createDuration(input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - diffRes; - - if (isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (isNumber(input)) { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match - }; - } else if (!!(match = isoRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1; - duration = { - y: parseIso(match[2], sign), - M: parseIso(match[3], sign), - w: parseIso(match[4], sign), - d: parseIso(match[5], sign), - h: parseIso(match[6], sign), - m: parseIso(match[7], sign), - s: parseIso(match[8], sign) - }; - } else if (duration == null) {// checks for null or undefined - duration = {}; - } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) { - diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to)); - - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } - - ret = new Duration(duration); - - if (isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } - - return ret; - } - - createDuration.fn = Duration.prototype; - createDuration.invalid = createInvalid$1; - - function parseIso(inp, sign) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - } - - function positiveMomentsDifference(base, other) { - var res = { milliseconds: 0, months: 0 }; - - res.months = other.month() - base.month() + - (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } - - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - - return res; - } - - function momentsDifference(base, other) { - var res; - if (!(base.isValid() && other.isValid())) { - return { milliseconds: 0, months: 0 }; - } - - other = cloneWithOffset(other, base); - if (base.isBefore(other)) { - res = positiveMomentsDifference(base, other); - } else { - res = positiveMomentsDifference(other, base); - res.milliseconds = -res.milliseconds; - res.months = -res.months; - } - - return res; - } - - // TODO: remove 'name' arg after deprecation is removed - function createAdder(direction, name) { - return function (val, period) { - var dur, tmp; - //invert the arguments, but complain about it - if (period !== null && !isNaN(+period)) { - deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' + - 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.'); - tmp = val; val = period; period = tmp; - } - - val = typeof val === 'string' ? +val : val; - dur = createDuration(val, period); - addSubtract(this, dur, direction); - return this; - }; - } - - function addSubtract(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = absRound(duration._days), - months = absRound(duration._months); - - if (!mom.isValid()) { - // No op - return; - } - - updateOffset = updateOffset == null ? true : updateOffset; - - if (months) { - setMonth(mom, get(mom, 'Month') + months * isAdding); - } - if (days) { - set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); - } - if (milliseconds) { - mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); - } - if (updateOffset) { - hooks.updateOffset(mom, days || months); - } - } - - var add = createAdder(1, 'add'); - var subtract = createAdder(-1, 'subtract'); - - function getCalendarFormat(myMoment, now) { - var diff = myMoment.diff(now, 'days', true); - return diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - } - - function calendar$1(time, formats) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're local/utc/offset or not. - var now = time || createLocal(), - sod = cloneWithOffset(now, this).startOf('day'), - format = hooks.calendarFormat(this, sod) || 'sameElse'; - - var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]); - - return this.format(output || this.localeData().calendar(format, this, createLocal(now))); - } - - function clone() { - return new Moment(this); - } - - function isAfter(input, units) { - var localInput = isMoment(input) ? input : createLocal(input); - if (!(this.isValid() && localInput.isValid())) { - return false; - } - units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); - if (units === 'millisecond') { - return this.valueOf() > localInput.valueOf(); - } else { - return localInput.valueOf() < this.clone().startOf(units).valueOf(); - } - } - - function isBefore(input, units) { - var localInput = isMoment(input) ? input : createLocal(input); - if (!(this.isValid() && localInput.isValid())) { - return false; - } - units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); - if (units === 'millisecond') { - return this.valueOf() < localInput.valueOf(); - } else { - return this.clone().endOf(units).valueOf() < localInput.valueOf(); - } - } - - function isBetween(from, to, units, inclusivity) { - inclusivity = inclusivity || '()'; - return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) && - (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units)); - } - - function isSame(input, units) { - var localInput = isMoment(input) ? input : createLocal(input), - inputMs; - if (!(this.isValid() && localInput.isValid())) { - return false; - } - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - return this.valueOf() === localInput.valueOf(); - } else { - inputMs = localInput.valueOf(); - return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf(); - } - } - - function isSameOrAfter(input, units) { - return this.isSame(input, units) || this.isAfter(input, units); - } - - function isSameOrBefore(input, units) { - return this.isSame(input, units) || this.isBefore(input, units); - } - - function diff(input, units, asFloat) { - var that, - zoneDelta, - delta, output; - - if (!this.isValid()) { - return NaN; - } - - that = cloneWithOffset(input, this); - - if (!that.isValid()) { - return NaN; - } - - zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; - - units = normalizeUnits(units); - - switch (units) { - case 'year': output = monthDiff(this, that) / 12; break; - case 'month': output = monthDiff(this, that); break; - case 'quarter': output = monthDiff(this, that) / 3; break; - case 'second': output = (this - that) / 1e3; break; // 1000 - case 'minute': output = (this - that) / 6e4; break; // 1000 * 60 - case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60 - case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst - case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst - default: output = this - that; - } - - return asFloat ? output : absFloor(output); - } - - function monthDiff(a, b) { - // difference in months - var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), - // b is in (anchor - 1 month, anchor + 1 month) - anchor = a.clone().add(wholeMonthDiff, 'months'), - anchor2, adjust; - - if (b - anchor < 0) { - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor - anchor2); - } else { - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor2 - anchor); - } - - //check for negative zero, return zero if negative zero - return -(wholeMonthDiff + adjust) || 0; - } - - hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; - hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; - - function toString() { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - } - - function toISOString(keepOffset) { - if (!this.isValid()) { - return null; - } - var utc = keepOffset !== true; - var m = utc ? this.clone().utc() : this; - if (m.year() < 0 || m.year() > 9999) { - return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ'); - } - if (isFunction(Date.prototype.toISOString)) { - // native implementation is ~50x faster, use it when we can - if (utc) { - return this.toDate().toISOString(); - } else { - return new Date(this._d.valueOf()).toISOString().replace('Z', formatMoment(m, 'Z')); - } - } - return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ'); - } - - /** - * Return a human readable representation of a moment that can - * also be evaluated to get a new moment which is the same - * - * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects - */ - function inspect() { - if (!this.isValid()) { - return 'moment.invalid(/* ' + this._i + ' */)'; - } - var func = 'moment'; - var zone = ''; - if (!this.isLocal()) { - func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; - zone = 'Z'; - } - var prefix = '[' + func + '("]'; - var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY'; - var datetime = '-MM-DD[T]HH:mm:ss.SSS'; - var suffix = zone + '[")]'; - - return this.format(prefix + year + datetime + suffix); - } - - function format(inputString) { - if (!inputString) { - inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat; - } - var output = formatMoment(this, inputString); - return this.localeData().postformat(output); - } - - function from(time, withoutSuffix) { - if (this.isValid() && - ((isMoment(time) && time.isValid()) || - createLocal(time).isValid())) { - return createDuration({ to: this, from: time }).locale(this.locale()).humanize(!withoutSuffix); - } else { - return this.localeData().invalidDate(); - } - } - - function fromNow(withoutSuffix) { - return this.from(createLocal(), withoutSuffix); - } - - function to(time, withoutSuffix) { - if (this.isValid() && - ((isMoment(time) && time.isValid()) || - createLocal(time).isValid())) { - return createDuration({ from: this, to: time }).locale(this.locale()).humanize(!withoutSuffix); - } else { - return this.localeData().invalidDate(); - } - } - - function toNow(withoutSuffix) { - return this.to(createLocal(), withoutSuffix); - } - - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - function locale(key) { - var newLocaleData; - - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = getLocale(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - } - - var lang = deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ); - - function localeData() { - return this._locale; - } - - function startOf(units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - case 'date': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } - if (units === 'isoWeek') { - this.isoWeekday(1); - } - - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } - - return this; - } - - function endOf(units) { - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond') { - return this; - } - - // 'date' is an alias for 'day', so it should be considered as such. - if (units === 'date') { - units = 'day'; - } - - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - } - - function valueOf() { - return this._d.valueOf() - ((this._offset || 0) * 60000); - } - - function unix() { - return Math.floor(this.valueOf() / 1000); - } - - function toDate() { - return new Date(this.valueOf()); - } - - function toArray() { - var m = this; - return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; - } - - function toObject() { - var m = this; - return { - years: m.year(), - months: m.month(), - date: m.date(), - hours: m.hours(), - minutes: m.minutes(), - seconds: m.seconds(), - milliseconds: m.milliseconds() - }; - } - - function toJSON() { - // new Date(NaN).toJSON() === null - return this.isValid() ? this.toISOString() : null; - } - - function isValid$2() { - return isValid(this); - } - - function parsingFlags() { - return extend({}, getParsingFlags(this)); - } - - function invalidAt() { - return getParsingFlags(this).overflow; - } - - function creationData() { - return { - input: this._i, - format: this._f, - locale: this._locale, - isUTC: this._isUTC, - strict: this._strict - }; - } - - // FORMATTING - - addFormatToken(0, ['gg', 2], 0, function () { - return this.weekYear() % 100; - }); - - addFormatToken(0, ['GG', 2], 0, function () { - return this.isoWeekYear() % 100; - }); - - function addWeekYearFormatToken(token, getter) { - addFormatToken(0, [token, token.length], 0, getter); - } - - addWeekYearFormatToken('gggg', 'weekYear'); - addWeekYearFormatToken('ggggg', 'weekYear'); - addWeekYearFormatToken('GGGG', 'isoWeekYear'); - addWeekYearFormatToken('GGGGG', 'isoWeekYear'); - - // ALIASES - - addUnitAlias('weekYear', 'gg'); - addUnitAlias('isoWeekYear', 'GG'); - - // PRIORITY - - addUnitPriority('weekYear', 1); - addUnitPriority('isoWeekYear', 1); - - - // PARSING - - addRegexToken('G', matchSigned); - addRegexToken('g', matchSigned); - addRegexToken('GG', match1to2, match2); - addRegexToken('gg', match1to2, match2); - addRegexToken('GGGG', match1to4, match4); - addRegexToken('gggg', match1to4, match4); - addRegexToken('GGGGG', match1to6, match6); - addRegexToken('ggggg', match1to6, match6); - - addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) { - week[token.substr(0, 2)] = toInt(input); - }); - - addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { - week[token] = hooks.parseTwoDigitYear(input); - }); - - // MOMENTS - - function getSetWeekYear(input) { - return getSetWeekYearHelper.call(this, - input, - this.week(), - this.weekday(), - this.localeData()._week.dow, - this.localeData()._week.doy); - } - - function getSetISOWeekYear(input) { - return getSetWeekYearHelper.call(this, - input, this.isoWeek(), this.isoWeekday(), 1, 4); - } - - function getISOWeeksInYear() { - return weeksInYear(this.year(), 1, 4); - } - - function getWeeksInYear() { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - } - - function getSetWeekYearHelper(input, week, weekday, dow, doy) { - var weeksTarget; - if (input == null) { - return weekOfYear(this, dow, doy).year; - } else { - weeksTarget = weeksInYear(input, dow, doy); - if (week > weeksTarget) { - week = weeksTarget; - } - return setWeekAll.call(this, input, week, weekday, dow, doy); - } - } - - function setWeekAll(weekYear, week, weekday, dow, doy) { - var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), - date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); - - this.year(date.getUTCFullYear()); - this.month(date.getUTCMonth()); - this.date(date.getUTCDate()); - return this; - } - - // FORMATTING - - addFormatToken('Q', 0, 'Qo', 'quarter'); - - // ALIASES - - addUnitAlias('quarter', 'Q'); - - // PRIORITY - - addUnitPriority('quarter', 7); - - // PARSING - - addRegexToken('Q', match1); - addParseToken('Q', function (input, array) { - array[MONTH] = (toInt(input) - 1) * 3; - }); - - // MOMENTS - - function getSetQuarter(input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - } - - // FORMATTING - - addFormatToken('D', ['DD', 2], 'Do', 'date'); - - // ALIASES - - addUnitAlias('date', 'D'); - - // PRIOROITY - addUnitPriority('date', 9); - - // PARSING - - addRegexToken('D', match1to2); - addRegexToken('DD', match1to2, match2); - addRegexToken('Do', function (isStrict, locale) { - // TODO: Remove "ordinalParse" fallback in next major release. - return isStrict ? - (locale._dayOfMonthOrdinalParse || locale._ordinalParse) : - locale._dayOfMonthOrdinalParseLenient; - }); - - addParseToken(['D', 'DD'], DATE); - addParseToken('Do', function (input, array) { - array[DATE] = toInt(input.match(match1to2)[0]); - }); - - // MOMENTS - - var getSetDayOfMonth = makeGetSet('Date', true); - - // FORMATTING - - addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); - - // ALIASES - - addUnitAlias('dayOfYear', 'DDD'); - - // PRIORITY - addUnitPriority('dayOfYear', 4); - - // PARSING - - addRegexToken('DDD', match1to3); - addRegexToken('DDDD', match3); - addParseToken(['DDD', 'DDDD'], function (input, array, config) { - config._dayOfYear = toInt(input); - }); - - // HELPERS - - // MOMENTS - - function getSetDayOfYear(input) { - var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - } - - // FORMATTING - - addFormatToken('m', ['mm', 2], 0, 'minute'); - - // ALIASES - - addUnitAlias('minute', 'm'); - - // PRIORITY - - addUnitPriority('minute', 14); - - // PARSING - - addRegexToken('m', match1to2); - addRegexToken('mm', match1to2, match2); - addParseToken(['m', 'mm'], MINUTE); - - // MOMENTS - - var getSetMinute = makeGetSet('Minutes', false); - - // FORMATTING - - addFormatToken('s', ['ss', 2], 0, 'second'); - - // ALIASES - - addUnitAlias('second', 's'); - - // PRIORITY - - addUnitPriority('second', 15); - - // PARSING - - addRegexToken('s', match1to2); - addRegexToken('ss', match1to2, match2); - addParseToken(['s', 'ss'], SECOND); - - // MOMENTS - - var getSetSecond = makeGetSet('Seconds', false); - - // FORMATTING - - addFormatToken('S', 0, 0, function () { - return ~~(this.millisecond() / 100); - }); - - addFormatToken(0, ['SS', 2], 0, function () { - return ~~(this.millisecond() / 10); - }); - - addFormatToken(0, ['SSS', 3], 0, 'millisecond'); - addFormatToken(0, ['SSSS', 4], 0, function () { - return this.millisecond() * 10; - }); - addFormatToken(0, ['SSSSS', 5], 0, function () { - return this.millisecond() * 100; - }); - addFormatToken(0, ['SSSSSS', 6], 0, function () { - return this.millisecond() * 1000; - }); - addFormatToken(0, ['SSSSSSS', 7], 0, function () { - return this.millisecond() * 10000; - }); - addFormatToken(0, ['SSSSSSSS', 8], 0, function () { - return this.millisecond() * 100000; - }); - addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { - return this.millisecond() * 1000000; - }); - - - // ALIASES - - addUnitAlias('millisecond', 'ms'); - - // PRIORITY - - addUnitPriority('millisecond', 16); - - // PARSING - - addRegexToken('S', match1to3, match1); - addRegexToken('SS', match1to3, match2); - addRegexToken('SSS', match1to3, match3); - - var token; - for (token = 'SSSS'; token.length <= 9; token += 'S') { - addRegexToken(token, matchUnsigned); - } - - function parseMs(input, array) { - array[MILLISECOND] = toInt(('0.' + input) * 1000); - } - - for (token = 'S'; token.length <= 9; token += 'S') { - addParseToken(token, parseMs); - } - // MOMENTS - - var getSetMillisecond = makeGetSet('Milliseconds', false); - - // FORMATTING - - addFormatToken('z', 0, 0, 'zoneAbbr'); - addFormatToken('zz', 0, 0, 'zoneName'); - - // MOMENTS - - function getZoneAbbr() { - return this._isUTC ? 'UTC' : ''; - } - - function getZoneName() { - return this._isUTC ? 'Coordinated Universal Time' : ''; - } - - var proto = Moment.prototype; - - proto.add = add; - proto.calendar = calendar$1; - proto.clone = clone; - proto.diff = diff; - proto.endOf = endOf; - proto.format = format; - proto.from = from; - proto.fromNow = fromNow; - proto.to = to; - proto.toNow = toNow; - proto.get = stringGet; - proto.invalidAt = invalidAt; - proto.isAfter = isAfter; - proto.isBefore = isBefore; - proto.isBetween = isBetween; - proto.isSame = isSame; - proto.isSameOrAfter = isSameOrAfter; - proto.isSameOrBefore = isSameOrBefore; - proto.isValid = isValid$2; - proto.lang = lang; - proto.locale = locale; - proto.localeData = localeData; - proto.max = prototypeMax; - proto.min = prototypeMin; - proto.parsingFlags = parsingFlags; - proto.set = stringSet; - proto.startOf = startOf; - proto.subtract = subtract; - proto.toArray = toArray; - proto.toObject = toObject; - proto.toDate = toDate; - proto.toISOString = toISOString; - proto.inspect = inspect; - proto.toJSON = toJSON; - proto.toString = toString; - proto.unix = unix; - proto.valueOf = valueOf; - proto.creationData = creationData; - - // Year - proto.year = getSetYear; - proto.isLeapYear = getIsLeapYear; - - // Week Year - proto.weekYear = getSetWeekYear; - proto.isoWeekYear = getSetISOWeekYear; - - // Quarter - proto.quarter = proto.quarters = getSetQuarter; - - // Month - proto.month = getSetMonth; - proto.daysInMonth = getDaysInMonth; - - // Week - proto.week = proto.weeks = getSetWeek; - proto.isoWeek = proto.isoWeeks = getSetISOWeek; - proto.weeksInYear = getWeeksInYear; - proto.isoWeeksInYear = getISOWeeksInYear; - - // Day - proto.date = getSetDayOfMonth; - proto.day = proto.days = getSetDayOfWeek; - proto.weekday = getSetLocaleDayOfWeek; - proto.isoWeekday = getSetISODayOfWeek; - proto.dayOfYear = getSetDayOfYear; - - // Hour - proto.hour = proto.hours = getSetHour; - - // Minute - proto.minute = proto.minutes = getSetMinute; - - // Second - proto.second = proto.seconds = getSetSecond; - - // Millisecond - proto.millisecond = proto.milliseconds = getSetMillisecond; - - // Offset - proto.utcOffset = getSetOffset; - proto.utc = setOffsetToUTC; - proto.local = setOffsetToLocal; - proto.parseZone = setOffsetToParsedOffset; - proto.hasAlignedHourOffset = hasAlignedHourOffset; - proto.isDST = isDaylightSavingTime; - proto.isLocal = isLocal; - proto.isUtcOffset = isUtcOffset; - proto.isUtc = isUtc; - proto.isUTC = isUtc; - - // Timezone - proto.zoneAbbr = getZoneAbbr; - proto.zoneName = getZoneName; - - // Deprecations - proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth); - proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth); - proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear); - proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone); - proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted); - - function createUnix(input) { - return createLocal(input * 1000); - } - - function createInZone() { - return createLocal.apply(null, arguments).parseZone(); - } - - function preParsePostFormat(string) { - return string; - } - - var proto$1 = Locale.prototype; - - proto$1.calendar = calendar; - proto$1.longDateFormat = longDateFormat; - proto$1.invalidDate = invalidDate; - proto$1.ordinal = ordinal; - proto$1.preparse = preParsePostFormat; - proto$1.postformat = preParsePostFormat; - proto$1.relativeTime = relativeTime; - proto$1.pastFuture = pastFuture; - proto$1.set = set; - - // Month - proto$1.months = localeMonths; - proto$1.monthsShort = localeMonthsShort; - proto$1.monthsParse = localeMonthsParse; - proto$1.monthsRegex = monthsRegex; - proto$1.monthsShortRegex = monthsShortRegex; - - // Week - proto$1.week = localeWeek; - proto$1.firstDayOfYear = localeFirstDayOfYear; - proto$1.firstDayOfWeek = localeFirstDayOfWeek; - - // Day of Week - proto$1.weekdays = localeWeekdays; - proto$1.weekdaysMin = localeWeekdaysMin; - proto$1.weekdaysShort = localeWeekdaysShort; - proto$1.weekdaysParse = localeWeekdaysParse; - - proto$1.weekdaysRegex = weekdaysRegex; - proto$1.weekdaysShortRegex = weekdaysShortRegex; - proto$1.weekdaysMinRegex = weekdaysMinRegex; - - // Hours - proto$1.isPM = localeIsPM; - proto$1.meridiem = localeMeridiem; - - function get$1(format, index, field, setter) { - var locale = getLocale(); - var utc = createUTC().set(setter, index); - return locale[field](utc, format); - } - - function listMonthsImpl(format, index, field) { - if (isNumber(format)) { - index = format; - format = undefined; - } - - format = format || ''; - - if (index != null) { - return get$1(format, index, field, 'month'); - } - - var i; - var out = []; - for (i = 0; i < 12; i++) { - out[i] = get$1(format, i, field, 'month'); - } - return out; - } - - // () - // (5) - // (fmt, 5) - // (fmt) - // (true) - // (true, 5) - // (true, fmt, 5) - // (true, fmt) - function listWeekdaysImpl(localeSorted, format, index, field) { - if (typeof localeSorted === 'boolean') { - if (isNumber(format)) { - index = format; - format = undefined; - } - - format = format || ''; - } else { - format = localeSorted; - index = format; - localeSorted = false; - - if (isNumber(format)) { - index = format; - format = undefined; - } - - format = format || ''; - } - - var locale = getLocale(), - shift = localeSorted ? locale._week.dow : 0; - - if (index != null) { - return get$1(format, (index + shift) % 7, field, 'day'); - } - - var i; - var out = []; - for (i = 0; i < 7; i++) { - out[i] = get$1(format, (i + shift) % 7, field, 'day'); - } - return out; - } - - function listMonths(format, index) { - return listMonthsImpl(format, index, 'months'); - } - - function listMonthsShort(format, index) { - return listMonthsImpl(format, index, 'monthsShort'); - } - - function listWeekdays(localeSorted, format, index) { - return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); - } - - function listWeekdaysShort(localeSorted, format, index) { - return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); - } - - function listWeekdaysMin(localeSorted, format, index) { - return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); - } - - getSetGlobalLocale('en', { - dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal: function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - // Side effect imports - hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale); - hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale); - - var mathAbs = Math.abs; - - function abs() { - var data = this._data; - - this._milliseconds = mathAbs(this._milliseconds); - this._days = mathAbs(this._days); - this._months = mathAbs(this._months); - - data.milliseconds = mathAbs(data.milliseconds); - data.seconds = mathAbs(data.seconds); - data.minutes = mathAbs(data.minutes); - data.hours = mathAbs(data.hours); - data.months = mathAbs(data.months); - data.years = mathAbs(data.years); - - return this; - } - - function addSubtract$1(duration, input, value, direction) { - var other = createDuration(input, value); - - duration._milliseconds += direction * other._milliseconds; - duration._days += direction * other._days; - duration._months += direction * other._months; - - return duration._bubble(); - } - - // supports only 2.0-style add(1, 's') or add(duration) - function add$1(input, value) { - return addSubtract$1(this, input, value, 1); - } - - // supports only 2.0-style subtract(1, 's') or subtract(duration) - function subtract$1(input, value) { - return addSubtract$1(this, input, value, -1); - } - - function absCeil(number) { - if (number < 0) { - return Math.floor(number); - } else { - return Math.ceil(number); - } - } - - function bubble() { - var milliseconds = this._milliseconds; - var days = this._days; - var months = this._months; - var data = this._data; - var seconds, minutes, hours, years, monthsFromDays; - - // if we have a mix of positive and negative values, bubble down first - // check: https://github.com/moment/moment/issues/2166 - if (!((milliseconds >= 0 && days >= 0 && months >= 0) || - (milliseconds <= 0 && days <= 0 && months <= 0))) { - milliseconds += absCeil(monthsToDays(months) + days) * 864e5; - days = 0; - months = 0; - } - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absFloor(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absFloor(seconds / 60); - data.minutes = minutes % 60; - - hours = absFloor(minutes / 60); - data.hours = hours % 24; - - days += absFloor(hours / 24); - - // convert days to months - monthsFromDays = absFloor(daysToMonths(days)); - months += monthsFromDays; - days -= absCeil(monthsToDays(monthsFromDays)); - - // 12 months -> 1 year - years = absFloor(months / 12); - months %= 12; - - data.days = days; - data.months = months; - data.years = years; - - return this; - } - - function daysToMonths(days) { - // 400 years have 146097 days (taking into account leap year rules) - // 400 years have 12 months === 4800 - return days * 4800 / 146097; - } - - function monthsToDays(months) { - // the reverse of daysToMonths - return months * 146097 / 4800; - } - - function as(units) { - if (!this.isValid()) { - return NaN; - } - var days; - var months; - var milliseconds = this._milliseconds; - - units = normalizeUnits(units); - - if (units === 'month' || units === 'year') { - days = this._days + milliseconds / 864e5; - months = this._months + daysToMonths(days); - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(monthsToDays(this._months)); - switch (units) { - case 'week': return days / 7 + milliseconds / 6048e5; - case 'day': return days + milliseconds / 864e5; - case 'hour': return days * 24 + milliseconds / 36e5; - case 'minute': return days * 1440 + milliseconds / 6e4; - case 'second': return days * 86400 + milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 864e5) + milliseconds; - default: throw new Error('Unknown unit ' + units); - } - } - } - - // TODO: Use this.as('ms')? - function valueOf$1() { - if (!this.isValid()) { - return NaN; - } - return ( - this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6 - ); - } - - function makeAs(alias) { - return function () { - return this.as(alias); - }; - } - - var asMilliseconds = makeAs('ms'); - var asSeconds = makeAs('s'); - var asMinutes = makeAs('m'); - var asHours = makeAs('h'); - var asDays = makeAs('d'); - var asWeeks = makeAs('w'); - var asMonths = makeAs('M'); - var asYears = makeAs('y'); - - function clone$1() { - return createDuration(this); - } - - function get$2(units) { - units = normalizeUnits(units); - return this.isValid() ? this[units + 's']() : NaN; - } - - function makeGetter(name) { - return function () { - return this.isValid() ? this._data[name] : NaN; - }; - } - - var milliseconds = makeGetter('milliseconds'); - var seconds = makeGetter('seconds'); - var minutes = makeGetter('minutes'); - var hours = makeGetter('hours'); - var days = makeGetter('days'); - var months = makeGetter('months'); - var years = makeGetter('years'); - - function weeks() { - return absFloor(this.days() / 7); - } - - var round = Math.round; - var thresholds = { - ss: 44, // a few seconds to seconds - s: 45, // seconds to minute - m: 45, // minutes to hour - h: 22, // hours to day - d: 26, // days to month - M: 11 // months to year - }; - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime$1(posNegDuration, withoutSuffix, locale) { - var duration = createDuration(posNegDuration).abs(); - var seconds = round(duration.as('s')); - var minutes = round(duration.as('m')); - var hours = round(duration.as('h')); - var days = round(duration.as('d')); - var months = round(duration.as('M')); - var years = round(duration.as('y')); - - var a = seconds <= thresholds.ss && ['s', seconds] || - seconds < thresholds.s && ['ss', seconds] || - minutes <= 1 && ['m'] || - minutes < thresholds.m && ['mm', minutes] || - hours <= 1 && ['h'] || - hours < thresholds.h && ['hh', hours] || - days <= 1 && ['d'] || - days < thresholds.d && ['dd', days] || - months <= 1 && ['M'] || - months < thresholds.M && ['MM', months] || - years <= 1 && ['y'] || ['yy', years]; - - a[2] = withoutSuffix; - a[3] = +posNegDuration > 0; - a[4] = locale; - return substituteTimeAgo.apply(null, a); - } - - // This function allows you to set the rounding function for relative time strings - function getSetRelativeTimeRounding(roundingFunction) { - if (roundingFunction === undefined) { - return round; - } - if (typeof (roundingFunction) === 'function') { - round = roundingFunction; - return true; - } - return false; - } - - // This function allows you to set a threshold for relative time strings - function getSetRelativeTimeThreshold(threshold, limit) { - if (thresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return thresholds[threshold]; - } - thresholds[threshold] = limit; - if (threshold === 's') { - thresholds.ss = limit - 1; - } - return true; - } - - function humanize(withSuffix) { - if (!this.isValid()) { - return this.localeData().invalidDate(); - } - - var locale = this.localeData(); - var output = relativeTime$1(this, !withSuffix, locale); - - if (withSuffix) { - output = locale.pastFuture(+this, output); - } - - return locale.postformat(output); - } - - var abs$1 = Math.abs; - - function sign(x) { - return ((x > 0) - (x < 0)) || +x; - } - - function toISOString$1() { - // for ISO strings we do not use the normal bubbling rules: - // * milliseconds bubble up until they become hours - // * days do not bubble at all - // * months bubble up until they become years - // This is because there is no context-free conversion between hours and days - // (think of clock changes) - // and also not between days and months (28-31 days per month) - if (!this.isValid()) { - return this.localeData().invalidDate(); - } - - var seconds = abs$1(this._milliseconds) / 1000; - var days = abs$1(this._days); - var months = abs$1(this._months); - var minutes, hours, years; - - // 3600 seconds -> 60 minutes -> 1 hour - minutes = absFloor(seconds / 60); - hours = absFloor(minutes / 60); - seconds %= 60; - minutes %= 60; - - // 12 months -> 1 year - years = absFloor(months / 12); - months %= 12; - - - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var Y = years; - var M = months; - var D = days; - var h = hours; - var m = minutes; - var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : ''; - var total = this.asSeconds(); - - if (!total) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - - var totalSign = total < 0 ? '-' : ''; - var ymSign = sign(this._months) !== sign(total) ? '-' : ''; - var daysSign = sign(this._days) !== sign(total) ? '-' : ''; - var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : ''; - - return totalSign + 'P' + - (Y ? ymSign + Y + 'Y' : '') + - (M ? ymSign + M + 'M' : '') + - (D ? daysSign + D + 'D' : '') + - ((h || m || s) ? 'T' : '') + - (h ? hmsSign + h + 'H' : '') + - (m ? hmsSign + m + 'M' : '') + - (s ? hmsSign + s + 'S' : ''); - } - - var proto$2 = Duration.prototype; - - proto$2.isValid = isValid$1; - proto$2.abs = abs; - proto$2.add = add$1; - proto$2.subtract = subtract$1; - proto$2.as = as; - proto$2.asMilliseconds = asMilliseconds; - proto$2.asSeconds = asSeconds; - proto$2.asMinutes = asMinutes; - proto$2.asHours = asHours; - proto$2.asDays = asDays; - proto$2.asWeeks = asWeeks; - proto$2.asMonths = asMonths; - proto$2.asYears = asYears; - proto$2.valueOf = valueOf$1; - proto$2._bubble = bubble; - proto$2.clone = clone$1; - proto$2.get = get$2; - proto$2.milliseconds = milliseconds; - proto$2.seconds = seconds; - proto$2.minutes = minutes; - proto$2.hours = hours; - proto$2.days = days; - proto$2.weeks = weeks; - proto$2.months = months; - proto$2.years = years; - proto$2.humanize = humanize; - proto$2.toISOString = toISOString$1; - proto$2.toString = toISOString$1; - proto$2.toJSON = toISOString$1; - proto$2.locale = locale; - proto$2.localeData = localeData; - - // Deprecations - proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1); - proto$2.lang = lang; - - // Side effect imports - - // FORMATTING - - addFormatToken('X', 0, 0, 'unix'); - addFormatToken('x', 0, 0, 'valueOf'); - - // PARSING - - addRegexToken('x', matchSigned); - addRegexToken('X', matchTimestamp); - addParseToken('X', function (input, array, config) { - config._d = new Date(parseFloat(input, 10) * 1000); - }); - addParseToken('x', function (input, array, config) { - config._d = new Date(toInt(input)); - }); - - // Side effect imports - - - hooks.version = '2.20.1'; - - setHookCallback(createLocal); - - hooks.fn = proto; - hooks.min = min; - hooks.max = max; - hooks.now = now; - hooks.utc = createUTC; - hooks.unix = createUnix; - hooks.months = listMonths; - hooks.isDate = isDate; - hooks.locale = getSetGlobalLocale; - hooks.invalid = createInvalid; - hooks.duration = createDuration; - hooks.isMoment = isMoment; - hooks.weekdays = listWeekdays; - hooks.parseZone = createInZone; - hooks.localeData = getLocale; - hooks.isDuration = isDuration; - hooks.monthsShort = listMonthsShort; - hooks.weekdaysMin = listWeekdaysMin; - hooks.defineLocale = defineLocale; - hooks.updateLocale = updateLocale; - hooks.locales = listLocales; - hooks.weekdaysShort = listWeekdaysShort; - hooks.normalizeUnits = normalizeUnits; - hooks.relativeTimeRounding = getSetRelativeTimeRounding; - hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; - hooks.calendarFormat = getCalendarFormat; - hooks.prototype = proto; - - // currently HTML5 input type only supports 24-hour formats - hooks.HTML5_FMT = { - DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // - DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // - DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // - DATE: 'YYYY-MM-DD', // - TIME: 'HH:mm', // - TIME_SECONDS: 'HH:mm:ss', // - TIME_MS: 'HH:mm:ss.SSS', // - WEEK: 'YYYY-[W]WW', // - MONTH: 'YYYY-MM' // - }; - - return hooks; - - }))); - - }, {}], 7: [function (require, module, exports) { - /** - * @namespace Chart - */ - var Chart = require(29)(); - - Chart.helpers = require(45); - - // @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests! - require(27)(Chart); - - Chart.defaults = require(25); - Chart.Element = require(26); - Chart.elements = require(40); - Chart.Interaction = require(28); - Chart.layouts = require(30); - Chart.platform = require(48); - Chart.plugins = require(31); - Chart.Ticks = require(34); - - require(22)(Chart); - require(23)(Chart); - require(24)(Chart); - require(33)(Chart); - require(32)(Chart); - require(35)(Chart); - - require(55)(Chart); - require(53)(Chart); - require(54)(Chart); - require(56)(Chart); - require(57)(Chart); - require(58)(Chart); - - // Controllers must be loaded after elements - // See Chart.core.datasetController.dataElementType - require(15)(Chart); - require(16)(Chart); - require(17)(Chart); - require(18)(Chart); - require(19)(Chart); - require(20)(Chart); - require(21)(Chart); - - require(8)(Chart); - require(9)(Chart); - require(10)(Chart); - require(11)(Chart); - require(12)(Chart); - require(13)(Chart); - require(14)(Chart); - - // Loading built-it plugins - var plugins = require(49); - for (var k in plugins) { - if (plugins.hasOwnProperty(k)) { - Chart.plugins.register(plugins[k]); - } - } - - Chart.platform.initialize(); - - module.exports = Chart; - if (typeof window !== 'undefined') { - window.Chart = Chart; - } - - // DEPRECATIONS - - /** - * Provided for backward compatibility, not available anymore - * @namespace Chart.Legend - * @deprecated since version 2.1.5 - * @todo remove at version 3 - * @private - */ - Chart.Legend = plugins.legend._element; - - /** - * Provided for backward compatibility, not available anymore - * @namespace Chart.Title - * @deprecated since version 2.1.5 - * @todo remove at version 3 - * @private - */ - Chart.Title = plugins.title._element; - - /** - * Provided for backward compatibility, use Chart.plugins instead - * @namespace Chart.pluginService - * @deprecated since version 2.1.5 - * @todo remove at version 3 - * @private - */ - Chart.pluginService = Chart.plugins; - - /** - * Provided for backward compatibility, inheriting from Chart.PlugingBase has no - * effect, instead simply create/register plugins via plain JavaScript objects. - * @interface Chart.PluginBase - * @deprecated since version 2.5.0 - * @todo remove at version 3 - * @private - */ - Chart.PluginBase = Chart.Element.extend({}); - - /** - * Provided for backward compatibility, use Chart.helpers.canvas instead. - * @namespace Chart.canvasHelpers - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ - Chart.canvasHelpers = Chart.helpers.canvas; - - /** - * Provided for backward compatibility, use Chart.layouts instead. - * @namespace Chart.layoutService - * @deprecated since version 2.8.0 - * @todo remove at version 3 - * @private - */ - Chart.layoutService = Chart.layouts; - - }, { "10": 10, "11": 11, "12": 12, "13": 13, "14": 14, "15": 15, "16": 16, "17": 17, "18": 18, "19": 19, "20": 20, "21": 21, "22": 22, "23": 23, "24": 24, "25": 25, "26": 26, "27": 27, "28": 28, "29": 29, "30": 30, "31": 31, "32": 32, "33": 33, "34": 34, "35": 35, "40": 40, "45": 45, "48": 48, "49": 49, "53": 53, "54": 54, "55": 55, "56": 56, "57": 57, "58": 58, "8": 8, "9": 9 }], 8: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - Chart.Bar = function (context, config) { - config.type = 'bar'; - - return new Chart(context, config); - }; - - }; - - }, {}], 9: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - Chart.Bubble = function (context, config) { - config.type = 'bubble'; - return new Chart(context, config); - }; - - }; - - }, {}], 10: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - Chart.Doughnut = function (context, config) { - config.type = 'doughnut'; - - return new Chart(context, config); - }; - - }; - - }, {}], 11: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - Chart.Line = function (context, config) { - config.type = 'line'; - - return new Chart(context, config); - }; - - }; - - }, {}], 12: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - Chart.PolarArea = function (context, config) { - config.type = 'polarArea'; - - return new Chart(context, config); - }; - - }; - - }, {}], 13: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - Chart.Radar = function (context, config) { - config.type = 'radar'; - - return new Chart(context, config); - }; - - }; - - }, {}], 14: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - Chart.Scatter = function (context, config) { - config.type = 'scatter'; - return new Chart(context, config); - }; - }; - - }, {}], 15: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('bar', { - hover: { - mode: 'label' - }, - - scales: { - xAxes: [{ - type: 'category', - - // Specific to Bar Controller - categoryPercentage: 0.8, - barPercentage: 0.9, - - // offset settings - offset: true, - - // grid line settings - gridLines: { - offsetGridLines: true - } - }], - - yAxes: [{ - type: 'linear' - }] - } - }); - - defaults._set('horizontalBar', { - hover: { - mode: 'index', - axis: 'y' - }, - - scales: { - xAxes: [{ - type: 'linear', - position: 'bottom' - }], - - yAxes: [{ - position: 'left', - type: 'category', - - // Specific to Horizontal Bar Controller - categoryPercentage: 0.8, - barPercentage: 0.9, - - // offset settings - offset: true, - - // grid line settings - gridLines: { - offsetGridLines: true - } - }] - }, - - elements: { - rectangle: { - borderSkipped: 'left' - } - }, - - tooltips: { - callbacks: { - title: function (item, data) { - // Pick first xLabel for now - var title = ''; - - if (item.length > 0) { - if (item[0].yLabel) { - title = item[0].yLabel; - } else if (data.labels.length > 0 && item[0].index < data.labels.length) { - title = data.labels[item[0].index]; - } - } - - return title; - }, - - label: function (item, data) { - var datasetLabel = data.datasets[item.datasetIndex].label || ''; - return datasetLabel + ': ' + item.xLabel; - } - }, - mode: 'index', - axis: 'y' - } - }); - - /** - * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap. - * @private - */ - function computeMinSampleSize(scale, pixels) { - var min = scale.isHorizontal() ? scale.width : scale.height; - var ticks = scale.getTicks(); - var prev, curr, i, ilen; - - for (i = 1, ilen = pixels.length; i < ilen; ++i) { - min = Math.min(min, pixels[i] - pixels[i - 1]); - } - - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - curr = scale.getPixelForTick(i); - min = i > 0 ? Math.min(min, curr - prev) : min; - prev = curr; - } - - return min; - } - - /** - * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null, - * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This - * mode currently always generates bars equally sized (until we introduce scriptable options?). - * @private - */ - function computeFitCategoryTraits(index, ruler, options) { - var thickness = options.barThickness; - var count = ruler.stackCount; - var curr = ruler.pixels[index]; - var size, ratio; - - if (helpers.isNullOrUndef(thickness)) { - size = ruler.min * options.categoryPercentage; - ratio = options.barPercentage; - } else { - // When bar thickness is enforced, category and bar percentages are ignored. - // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%') - // and deprecate barPercentage since this value is ignored when thickness is absolute. - size = thickness * count; - ratio = 1; - } - - return { - chunk: size / count, - ratio: ratio, - start: curr - (size / 2) - }; - } - - /** - * Computes an "optimal" category that globally arranges bars side by side (no gap when - * percentage options are 1), based on the previous and following categories. This mode - * generates bars with different widths when data are not evenly spaced. - * @private - */ - function computeFlexCategoryTraits(index, ruler, options) { - var pixels = ruler.pixels; - var curr = pixels[index]; - var prev = index > 0 ? pixels[index - 1] : null; - var next = index < pixels.length - 1 ? pixels[index + 1] : null; - var percent = options.categoryPercentage; - var start, size; - - if (prev === null) { - // first data: its size is double based on the next point or, - // if it's also the last data, we use the scale end extremity. - prev = curr - (next === null ? ruler.end - curr : next - curr); - } - - if (next === null) { - // last data: its size is also double based on the previous point. - next = curr + curr - prev; - } - - start = curr - ((curr - prev) / 2) * percent; - size = ((next - prev) / 2) * percent; - - return { - chunk: size / ruler.stackCount, - ratio: options.barPercentage, - start: start - }; - } - - module.exports = function (Chart) { - - Chart.controllers.bar = Chart.DatasetController.extend({ - - dataElementType: elements.Rectangle, - - initialize: function () { - var me = this; - var meta; - - Chart.DatasetController.prototype.initialize.apply(me, arguments); - - meta = me.getMeta(); - meta.stack = me.getDataset().stack; - meta.bar = true; - }, - - update: function (reset) { - var me = this; - var rects = me.getMeta().data; - var i, ilen; - - me._ruler = me.getRuler(); - - for (i = 0, ilen = rects.length; i < ilen; ++i) { - me.updateElement(rects[i], i, reset); - } - }, - - updateElement: function (rectangle, index, reset) { - var me = this; - var chart = me.chart; - var meta = me.getMeta(); - var dataset = me.getDataset(); - var custom = rectangle.custom || {}; - var rectangleOptions = chart.options.elements.rectangle; - - rectangle._xScale = me.getScaleForId(meta.xAxisID); - rectangle._yScale = me.getScaleForId(meta.yAxisID); - rectangle._datasetIndex = me.index; - rectangle._index = index; - - rectangle._model = { - datasetLabel: dataset.label, - label: chart.data.labels[index], - borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped, - backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor), - borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor), - borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth) - }; - - me.updateElementGeometry(rectangle, index, reset); - - rectangle.pivot(); - }, - - /** - * @private - */ - updateElementGeometry: function (rectangle, index, reset) { - var me = this; - var model = rectangle._model; - var vscale = me.getValueScale(); - var base = vscale.getBasePixel(); - var horizontal = vscale.isHorizontal(); - var ruler = me._ruler || me.getRuler(); - var vpixels = me.calculateBarValuePixels(me.index, index); - var ipixels = me.calculateBarIndexPixels(me.index, index, ruler); - - model.horizontal = horizontal; - model.base = reset ? base : vpixels.base; - model.x = horizontal ? reset ? base : vpixels.head : ipixels.center; - model.y = horizontal ? ipixels.center : reset ? base : vpixels.head; - model.height = horizontal ? ipixels.size : undefined; - model.width = horizontal ? undefined : ipixels.size; - }, - - /** - * @private - */ - getValueScaleId: function () { - return this.getMeta().yAxisID; - }, - - /** - * @private - */ - getIndexScaleId: function () { - return this.getMeta().xAxisID; - }, - - /** - * @private - */ - getValueScale: function () { - return this.getScaleForId(this.getValueScaleId()); - }, - - /** - * @private - */ - getIndexScale: function () { - return this.getScaleForId(this.getIndexScaleId()); - }, - - /** - * Returns the stacks based on groups and bar visibility. - * @param {Number} [last] - The dataset index - * @returns {Array} The stack list - * @private - */ - _getStacks: function (last) { - var me = this; - var chart = me.chart; - var scale = me.getIndexScale(); - var stacked = scale.options.stacked; - var ilen = last === undefined ? chart.data.datasets.length : last + 1; - var stacks = []; - var i, meta; - - for (i = 0; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - if (meta.bar && chart.isDatasetVisible(i) && - (stacked === false || - (stacked === true && stacks.indexOf(meta.stack) === -1) || - (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) { - stacks.push(meta.stack); - } - } - - return stacks; - }, - - /** - * Returns the effective number of stacks based on groups and bar visibility. - * @private - */ - getStackCount: function () { - return this._getStacks().length; - }, - - /** - * Returns the stack index for the given dataset based on groups and bar visibility. - * @param {Number} [datasetIndex] - The dataset index - * @param {String} [name] - The stack name to find - * @returns {Number} The stack index - * @private - */ - getStackIndex: function (datasetIndex, name) { - var stacks = this._getStacks(datasetIndex); - var index = (name !== undefined) - ? stacks.indexOf(name) - : -1; // indexOf returns -1 if element is not present - - return (index === -1) - ? stacks.length - 1 - : index; - }, - - /** - * @private - */ - getRuler: function () { - var me = this; - var scale = me.getIndexScale(); - var stackCount = me.getStackCount(); - var datasetIndex = me.index; - var isHorizontal = scale.isHorizontal(); - var start = isHorizontal ? scale.left : scale.top; - var end = start + (isHorizontal ? scale.width : scale.height); - var pixels = []; - var i, ilen, min; - - for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) { - pixels.push(scale.getPixelForValue(null, i, datasetIndex)); - } - - min = helpers.isNullOrUndef(scale.options.barThickness) - ? computeMinSampleSize(scale, pixels) - : -1; - - return { - min: min, - pixels: pixels, - start: start, - end: end, - stackCount: stackCount, - scale: scale - }; - }, - - /** - * Note: pixel values are not clamped to the scale area. - * @private - */ - calculateBarValuePixels: function (datasetIndex, index) { - var me = this; - var chart = me.chart; - var meta = me.getMeta(); - var scale = me.getValueScale(); - var datasets = chart.data.datasets; - var value = scale.getRightValue(datasets[datasetIndex].data[index]); - var stacked = scale.options.stacked; - var stack = meta.stack; - var start = 0; - var i, imeta, ivalue, base, head, size; - - if (stacked || (stacked === undefined && stack !== undefined)) { - for (i = 0; i < datasetIndex; ++i) { - imeta = chart.getDatasetMeta(i); - - if (imeta.bar && - imeta.stack === stack && - imeta.controller.getValueScaleId() === scale.id && - chart.isDatasetVisible(i)) { - - ivalue = scale.getRightValue(datasets[i].data[index]); - if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) { - start += ivalue; - } - } - } - } - - base = scale.getPixelForValue(start); - head = scale.getPixelForValue(start + value); - size = (head - base) / 2; - - return { - size: size, - base: base, - head: head, - center: head + size / 2 - }; - }, - - /** - * @private - */ - calculateBarIndexPixels: function (datasetIndex, index, ruler) { - var me = this; - var options = ruler.scale.options; - var range = options.barThickness === 'flex' - ? computeFlexCategoryTraits(index, ruler, options) - : computeFitCategoryTraits(index, ruler, options); - - var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack); - var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); - var size = Math.min( - helpers.valueOrDefault(options.maxBarThickness, Infinity), - range.chunk * range.ratio); - - return { - base: center - size / 2, - head: center + size / 2, - center: center, - size: size - }; - }, - - draw: function () { - var me = this; - var chart = me.chart; - var scale = me.getValueScale(); - var rects = me.getMeta().data; - var dataset = me.getDataset(); - var ilen = rects.length; - var i = 0; - - helpers.canvas.clipArea(chart.ctx, chart.chartArea); - - for (; i < ilen; ++i) { - if (!isNaN(scale.getRightValue(dataset.data[i]))) { - rects[i].draw(); - } - } - - helpers.canvas.unclipArea(chart.ctx); - }, - - setHoverStyle: function (rectangle) { - var dataset = this.chart.data.datasets[rectangle._datasetIndex]; - var index = rectangle._index; - var custom = rectangle.custom || {}; - var model = rectangle._model; - - model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); - model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor)); - model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); - }, - - removeHoverStyle: function (rectangle) { - var dataset = this.chart.data.datasets[rectangle._datasetIndex]; - var index = rectangle._index; - var custom = rectangle.custom || {}; - var model = rectangle._model; - var rectangleElementOptions = this.chart.options.elements.rectangle; - - model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor); - model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor); - model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth); - } - }); - - Chart.controllers.horizontalBar = Chart.controllers.bar.extend({ - /** - * @private - */ - getValueScaleId: function () { - return this.getMeta().xAxisID; - }, - - /** - * @private - */ - getIndexScaleId: function () { - return this.getMeta().yAxisID; - } - }); - }; - - }, { "25": 25, "40": 40, "45": 45 }], 16: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('bubble', { - hover: { - mode: 'single' - }, - - scales: { - xAxes: [{ - type: 'linear', // bubble should probably use a linear scale by default - position: 'bottom', - id: 'x-axis-0' // need an ID so datasets can reference the scale - }], - yAxes: [{ - type: 'linear', - position: 'left', - id: 'y-axis-0' - }] - }, - - tooltips: { - callbacks: { - title: function () { - // Title doesn't make sense for scatter since we format the data as a point - return ''; - }, - label: function (item, data) { - var datasetLabel = data.datasets[item.datasetIndex].label || ''; - var dataPoint = data.datasets[item.datasetIndex].data[item.index]; - return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')'; - } - } - } - }); - - - module.exports = function (Chart) { - - Chart.controllers.bubble = Chart.DatasetController.extend({ - /** - * @protected - */ - dataElementType: elements.Point, - - /** - * @protected - */ - update: function (reset) { - var me = this; - var meta = me.getMeta(); - var points = meta.data; - - // Update Points - helpers.each(points, function (point, index) { - me.updateElement(point, index, reset); - }); - }, - - /** - * @protected - */ - updateElement: function (point, index, reset) { - var me = this; - var meta = me.getMeta(); - var custom = point.custom || {}; - var xScale = me.getScaleForId(meta.xAxisID); - var yScale = me.getScaleForId(meta.yAxisID); - var options = me._resolveElementOptions(point, index); - var data = me.getDataset().data[index]; - var dsIndex = me.index; - - var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex); - var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex); - - point._xScale = xScale; - point._yScale = yScale; - point._options = options; - point._datasetIndex = dsIndex; - point._index = index; - point._model = { - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderWidth: options.borderWidth, - hitRadius: options.hitRadius, - pointStyle: options.pointStyle, - radius: reset ? 0 : options.radius, - skip: custom.skip || isNaN(x) || isNaN(y), - x: x, - y: y, - }; - - point.pivot(); - }, - - /** - * @protected - */ - setHoverStyle: function (point) { - var model = point._model; - var options = point._options; - - model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor)); - model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor)); - model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth); - model.radius = options.radius + options.hoverRadius; - }, - - /** - * @protected - */ - removeHoverStyle: function (point) { - var model = point._model; - var options = point._options; - - model.backgroundColor = options.backgroundColor; - model.borderColor = options.borderColor; - model.borderWidth = options.borderWidth; - model.radius = options.radius; - }, - - /** - * @private - */ - _resolveElementOptions: function (point, index) { - var me = this; - var chart = me.chart; - var datasets = chart.data.datasets; - var dataset = datasets[me.index]; - var custom = point.custom || {}; - var options = chart.options.elements.point; - var resolve = helpers.options.resolve; - var data = dataset.data[index]; - var values = {}; - var i, ilen, key; - - // Scriptable options - var context = { - chart: chart, - dataIndex: index, - dataset: dataset, - datasetIndex: me.index - }; - - var keys = [ - 'backgroundColor', - 'borderColor', - 'borderWidth', - 'hoverBackgroundColor', - 'hoverBorderColor', - 'hoverBorderWidth', - 'hoverRadius', - 'hitRadius', - 'pointStyle' - ]; - - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - values[key] = resolve([ - custom[key], - dataset[key], - options[key] - ], context, index); - } - - // Custom radius resolution - values.radius = resolve([ - custom.radius, - data ? data.r : undefined, - dataset.radius, - options.radius - ], context, index); - - return values; - } - }); - }; - - }, { "25": 25, "40": 40, "45": 45 }], 17: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('doughnut', { - animation: { - // Boolean - Whether we animate the rotation of the Doughnut - animateRotate: true, - // Boolean - Whether we animate scaling the Doughnut from the centre - animateScale: false - }, - hover: { - mode: 'single' - }, - legendCallback: function (chart) { - var text = []; - text.push('
    '); - - var data = chart.data; - var datasets = data.datasets; - var labels = data.labels; - - if (datasets.length) { - for (var i = 0; i < datasets[0].data.length; ++i) { - text.push('
  • '); - if (labels[i]) { - text.push(labels[i]); - } - text.push('
  • '); - } - } - - text.push('
'); - return text.join(''); - }, - legend: { - labels: { - generateLabels: function (chart) { - var data = chart.data; - if (data.labels.length && data.datasets.length) { - return data.labels.map(function (label, i) { - var meta = chart.getDatasetMeta(0); - var ds = data.datasets[0]; - var arc = meta.data[i]; - var custom = arc && arc.custom || {}; - var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; - var arcOpts = chart.options.elements.arc; - var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); - var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); - var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); - - return { - text: label, - fillStyle: fill, - strokeStyle: stroke, - lineWidth: bw, - hidden: isNaN(ds.data[i]) || meta.data[i].hidden, - - // Extra data used for toggling the correct item - index: i - }; - }); - } - return []; - } - }, - - onClick: function (e, legendItem) { - var index = legendItem.index; - var chart = this.chart; - var i, ilen, meta; - - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - // toggle visibility of index if exists - if (meta.data[index]) { - meta.data[index].hidden = !meta.data[index].hidden; - } - } - - chart.update(); - } - }, - - // The percentage of the chart that we cut out of the middle. - cutoutPercentage: 50, - - // The rotation of the chart, where the first data arc begins. - rotation: Math.PI * -0.5, - - // The total circumference of the chart. - circumference: Math.PI * 2.0, - - // Need to override these to give a nice default - tooltips: { - callbacks: { - title: function () { - return ''; - }, - label: function (tooltipItem, data) { - var dataLabel = data.labels[tooltipItem.index]; - var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; - - if (helpers.isArray(dataLabel)) { - // show value on first line of multiline label - // need to clone because we are changing the value - dataLabel = dataLabel.slice(); - dataLabel[0] += value; - } else { - dataLabel += value; - } - - return dataLabel; - } - } - } - }); - - defaults._set('pie', helpers.clone(defaults.doughnut)); - defaults._set('pie', { - cutoutPercentage: 0 - }); - - module.exports = function (Chart) { - - Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ - - dataElementType: elements.Arc, - - linkScales: helpers.noop, - - // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly - getRingIndex: function (datasetIndex) { - var ringIndex = 0; - - for (var j = 0; j < datasetIndex; ++j) { - if (this.chart.isDatasetVisible(j)) { - ++ringIndex; - } - } - - return ringIndex; - }, - - update: function (reset) { - var me = this; - var chart = me.chart; - var chartArea = chart.chartArea; - var opts = chart.options; - var arcOpts = opts.elements.arc; - var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth; - var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth; - var minSize = Math.min(availableWidth, availableHeight); - var offset = { x: 0, y: 0 }; - var meta = me.getMeta(); - var cutoutPercentage = opts.cutoutPercentage; - var circumference = opts.circumference; - - // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc - if (circumference < Math.PI * 2.0) { - var startAngle = opts.rotation % (Math.PI * 2.0); - startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0); - var endAngle = startAngle + circumference; - var start = { x: Math.cos(startAngle), y: Math.sin(startAngle) }; - var end = { x: Math.cos(endAngle), y: Math.sin(endAngle) }; - var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle); - var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle); - var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle); - var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle); - var cutout = cutoutPercentage / 100.0; - var min = { x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout)) }; - var max = { x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout)) }; - var size = { width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5 }; - minSize = Math.min(availableWidth / size.width, availableHeight / size.height); - offset = { x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5 }; - } - - chart.borderWidth = me.getMaxBorderWidth(meta.data); - chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0); - chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0); - chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); - chart.offsetX = offset.x * chart.outerRadius; - chart.offsetY = offset.y * chart.outerRadius; - - meta.total = me.calculateTotal(); - - me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index)); - me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0); - - helpers.each(meta.data, function (arc, index) { - me.updateElement(arc, index, reset); - }); - }, - - updateElement: function (arc, index, reset) { - var me = this; - var chart = me.chart; - var chartArea = chart.chartArea; - var opts = chart.options; - var animationOpts = opts.animation; - var centerX = (chartArea.left + chartArea.right) / 2; - var centerY = (chartArea.top + chartArea.bottom) / 2; - var startAngle = opts.rotation; // non reset case handled later - var endAngle = opts.rotation; // non reset case handled later - var dataset = me.getDataset(); - var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)); - var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius; - var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius; - var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; - - helpers.extend(arc, { - // Utility - _datasetIndex: me.index, - _index: index, - - // Desired view properties - _model: { - x: centerX + chart.offsetX, - y: centerY + chart.offsetY, - startAngle: startAngle, - endAngle: endAngle, - circumference: circumference, - outerRadius: outerRadius, - innerRadius: innerRadius, - label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index]) - } - }); - - var model = arc._model; - // Resets the visual styles - this.removeHoverStyle(arc); - - // Set correct angles if not resetting - if (!reset || !animationOpts.animateRotate) { - if (index === 0) { - model.startAngle = opts.rotation; - } else { - model.startAngle = me.getMeta().data[index - 1]._model.endAngle; - } - - model.endAngle = model.startAngle + model.circumference; - } - - arc.pivot(); - }, - - removeHoverStyle: function (arc) { - Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); - }, - - calculateTotal: function () { - var dataset = this.getDataset(); - var meta = this.getMeta(); - var total = 0; - var value; - - helpers.each(meta.data, function (element, index) { - value = dataset.data[index]; - if (!isNaN(value) && !element.hidden) { - total += Math.abs(value); - } - }); - - /* if (total === 0) { - total = NaN; - }*/ - - return total; - }, - - calculateCircumference: function (value) { - var total = this.getMeta().total; - if (total > 0 && !isNaN(value)) { - return (Math.PI * 2.0) * (Math.abs(value) / total); - } - return 0; - }, - - // gets the max border or hover width to properly scale pie charts - getMaxBorderWidth: function (arcs) { - var max = 0; - var index = this.index; - var length = arcs.length; - var borderWidth; - var hoverWidth; - - for (var i = 0; i < length; i++) { - borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0; - hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0; - - max = borderWidth > max ? borderWidth : max; - max = hoverWidth > max ? hoverWidth : max; - } - return max; - } - }); - }; - - }, { "25": 25, "40": 40, "45": 45 }], 18: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('line', { - showLines: true, - spanGaps: false, - - hover: { - mode: 'label' - }, - - scales: { - xAxes: [{ - type: 'category', - id: 'x-axis-0' - }], - yAxes: [{ - type: 'linear', - id: 'y-axis-0' - }] - } - }); - - module.exports = function (Chart) { - - function lineEnabled(dataset, options) { - return helpers.valueOrDefault(dataset.showLine, options.showLines); - } - - Chart.controllers.line = Chart.DatasetController.extend({ - - datasetElementType: elements.Line, - - dataElementType: elements.Point, - - update: function (reset) { - var me = this; - var meta = me.getMeta(); - var line = meta.dataset; - var points = meta.data || []; - var options = me.chart.options; - var lineElementOptions = options.elements.line; - var scale = me.getScaleForId(meta.yAxisID); - var i, ilen, custom; - var dataset = me.getDataset(); - var showLine = lineEnabled(dataset, options); - - // Update Line - if (showLine) { - custom = line.custom || {}; - - // Compatibility: If the properties are defined with only the old name, use those values - if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { - dataset.lineTension = dataset.tension; - } - - // Utility - line._scale = scale; - line._datasetIndex = me.index; - // Data - line._children = points; - // Model - line._model = { - // Appearance - // The default behavior of lines is to break at null values, according - // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158 - // This option gives lines the ability to span gaps - spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps, - tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension), - backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), - borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), - borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), - borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), - borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), - borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), - borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), - fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), - steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped), - cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode), - }; - - line.pivot(); - } - - // Update Points - for (i = 0, ilen = points.length; i < ilen; ++i) { - me.updateElement(points[i], i, reset); - } - - if (showLine && line._model.tension !== 0) { - me.updateBezierControlPoints(); - } - - // Now pivot the point for animation - for (i = 0, ilen = points.length; i < ilen; ++i) { - points[i].pivot(); - } - }, - - getPointBackgroundColor: function (point, index) { - var backgroundColor = this.chart.options.elements.point.backgroundColor; - var dataset = this.getDataset(); - var custom = point.custom || {}; - - if (custom.backgroundColor) { - backgroundColor = custom.backgroundColor; - } else if (dataset.pointBackgroundColor) { - backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor); - } else if (dataset.backgroundColor) { - backgroundColor = dataset.backgroundColor; - } - - return backgroundColor; - }, - - getPointBorderColor: function (point, index) { - var borderColor = this.chart.options.elements.point.borderColor; - var dataset = this.getDataset(); - var custom = point.custom || {}; - - if (custom.borderColor) { - borderColor = custom.borderColor; - } else if (dataset.pointBorderColor) { - borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor); - } else if (dataset.borderColor) { - borderColor = dataset.borderColor; - } - - return borderColor; - }, - - getPointBorderWidth: function (point, index) { - var borderWidth = this.chart.options.elements.point.borderWidth; - var dataset = this.getDataset(); - var custom = point.custom || {}; - - if (!isNaN(custom.borderWidth)) { - borderWidth = custom.borderWidth; - } else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) { - borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth); - } else if (!isNaN(dataset.borderWidth)) { - borderWidth = dataset.borderWidth; - } - - return borderWidth; - }, - - updateElement: function (point, index, reset) { - var me = this; - var meta = me.getMeta(); - var custom = point.custom || {}; - var dataset = me.getDataset(); - var datasetIndex = me.index; - var value = dataset.data[index]; - var yScale = me.getScaleForId(meta.yAxisID); - var xScale = me.getScaleForId(meta.xAxisID); - var pointOptions = me.chart.options.elements.point; - var x, y; - - // Compatibility: If the properties are defined with only the old name, use those values - if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) { - dataset.pointRadius = dataset.radius; - } - if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) { - dataset.pointHitRadius = dataset.hitRadius; - } - - x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex); - y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex); - - // Utility - point._xScale = xScale; - point._yScale = yScale; - point._datasetIndex = datasetIndex; - point._index = index; - - // Desired view properties - point._model = { - x: x, - y: y, - skip: custom.skip || isNaN(x) || isNaN(y), - // Appearance - radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius), - pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle), - backgroundColor: me.getPointBackgroundColor(point, index), - borderColor: me.getPointBorderColor(point, index), - borderWidth: me.getPointBorderWidth(point, index), - tension: meta.dataset._model ? meta.dataset._model.tension : 0, - steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false, - // Tooltip - hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius) - }; - }, - - calculatePointY: function (value, index, datasetIndex) { - var me = this; - var chart = me.chart; - var meta = me.getMeta(); - var yScale = me.getScaleForId(meta.yAxisID); - var sumPos = 0; - var sumNeg = 0; - var i, ds, dsMeta; - - if (yScale.options.stacked) { - for (i = 0; i < datasetIndex; i++) { - ds = chart.data.datasets[i]; - dsMeta = chart.getDatasetMeta(i); - if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) { - var stackedRightValue = Number(yScale.getRightValue(ds.data[index])); - if (stackedRightValue < 0) { - sumNeg += stackedRightValue || 0; - } else { - sumPos += stackedRightValue || 0; - } - } - } - - var rightValue = Number(yScale.getRightValue(value)); - if (rightValue < 0) { - return yScale.getPixelForValue(sumNeg + rightValue); - } - return yScale.getPixelForValue(sumPos + rightValue); - } - - return yScale.getPixelForValue(value); - }, - - updateBezierControlPoints: function () { - var me = this; - var meta = me.getMeta(); - var area = me.chart.chartArea; - var points = (meta.data || []); - var i, ilen, point, model, controlPoints; - - // Only consider points that are drawn in case the spanGaps option is used - if (meta.dataset._model.spanGaps) { - points = points.filter(function (pt) { - return !pt._model.skip; - }); - } - - function capControlPoint(pt, min, max) { - return Math.max(Math.min(pt, max), min); - } - - if (meta.dataset._model.cubicInterpolationMode === 'monotone') { - helpers.splineCurveMonotone(points); - } else { - for (i = 0, ilen = points.length; i < ilen; ++i) { - point = points[i]; - model = point._model; - controlPoints = helpers.splineCurve( - helpers.previousItem(points, i)._model, - model, - helpers.nextItem(points, i)._model, - meta.dataset._model.tension - ); - model.controlPointPreviousX = controlPoints.previous.x; - model.controlPointPreviousY = controlPoints.previous.y; - model.controlPointNextX = controlPoints.next.x; - model.controlPointNextY = controlPoints.next.y; - } - } - - if (me.chart.options.elements.line.capBezierPoints) { - for (i = 0, ilen = points.length; i < ilen; ++i) { - model = points[i]._model; - model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right); - model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom); - model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right); - model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom); - } - } - }, - - draw: function () { - var me = this; - var chart = me.chart; - var meta = me.getMeta(); - var points = meta.data || []; - var area = chart.chartArea; - var ilen = points.length; - var i = 0; - - helpers.canvas.clipArea(chart.ctx, area); - - if (lineEnabled(me.getDataset(), chart.options)) { - meta.dataset.draw(); - } - - helpers.canvas.unclipArea(chart.ctx); - - // Draw the points - for (; i < ilen; ++i) { - points[i].draw(area); - } - }, - - setHoverStyle: function (point) { - // Point - var dataset = this.chart.data.datasets[point._datasetIndex]; - var index = point._index; - var custom = point.custom || {}; - var model = point._model; - - model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); - model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); - model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor)); - model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth); - }, - - removeHoverStyle: function (point) { - var me = this; - var dataset = me.chart.data.datasets[point._datasetIndex]; - var index = point._index; - var custom = point.custom || {}; - var model = point._model; - - // Compatibility: If the properties are defined with only the old name, use those values - if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) { - dataset.pointRadius = dataset.radius; - } - - model.radius = custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius); - model.backgroundColor = me.getPointBackgroundColor(point, index); - model.borderColor = me.getPointBorderColor(point, index); - model.borderWidth = me.getPointBorderWidth(point, index); - } - }); - }; - - }, { "25": 25, "40": 40, "45": 45 }], 19: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('polarArea', { - scale: { - type: 'radialLinear', - angleLines: { - display: false - }, - gridLines: { - circular: true - }, - pointLabels: { - display: false - }, - ticks: { - beginAtZero: true - } - }, - - // Boolean - Whether to animate the rotation of the chart - animation: { - animateRotate: true, - animateScale: true - }, - - startAngle: -0.5 * Math.PI, - legendCallback: function (chart) { - var text = []; - text.push('
    '); - - var data = chart.data; - var datasets = data.datasets; - var labels = data.labels; - - if (datasets.length) { - for (var i = 0; i < datasets[0].data.length; ++i) { - text.push('
  • '); - if (labels[i]) { - text.push(labels[i]); - } - text.push('
  • '); - } - } - - text.push('
'); - return text.join(''); - }, - legend: { - labels: { - generateLabels: function (chart) { - var data = chart.data; - if (data.labels.length && data.datasets.length) { - return data.labels.map(function (label, i) { - var meta = chart.getDatasetMeta(0); - var ds = data.datasets[0]; - var arc = meta.data[i]; - var custom = arc.custom || {}; - var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; - var arcOpts = chart.options.elements.arc; - var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); - var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); - var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); - - return { - text: label, - fillStyle: fill, - strokeStyle: stroke, - lineWidth: bw, - hidden: isNaN(ds.data[i]) || meta.data[i].hidden, - - // Extra data used for toggling the correct item - index: i - }; - }); - } - return []; - } - }, - - onClick: function (e, legendItem) { - var index = legendItem.index; - var chart = this.chart; - var i, ilen, meta; - - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - meta.data[index].hidden = !meta.data[index].hidden; - } - - chart.update(); - } - }, - - // Need to override these to give a nice default - tooltips: { - callbacks: { - title: function () { - return ''; - }, - label: function (item, data) { - return data.labels[item.index] + ': ' + item.yLabel; - } - } - } - }); - - module.exports = function (Chart) { - - Chart.controllers.polarArea = Chart.DatasetController.extend({ - - dataElementType: elements.Arc, - - linkScales: helpers.noop, - - update: function (reset) { - var me = this; - var chart = me.chart; - var chartArea = chart.chartArea; - var meta = me.getMeta(); - var opts = chart.options; - var arcOpts = opts.elements.arc; - var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); - chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0); - chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); - chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); - - me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index); - me.innerRadius = me.outerRadius - chart.radiusLength; - - meta.count = me.countVisibleElements(); - - helpers.each(meta.data, function (arc, index) { - me.updateElement(arc, index, reset); - }); - }, - - updateElement: function (arc, index, reset) { - var me = this; - var chart = me.chart; - var dataset = me.getDataset(); - var opts = chart.options; - var animationOpts = opts.animation; - var scale = chart.scale; - var labels = chart.data.labels; - - var circumference = me.calculateCircumference(dataset.data[index]); - var centerX = scale.xCenter; - var centerY = scale.yCenter; - - // If there is NaN data before us, we need to calculate the starting angle correctly. - // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data - var visibleCount = 0; - var meta = me.getMeta(); - for (var i = 0; i < index; ++i) { - if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) { - ++visibleCount; - } - } - - // var negHalfPI = -0.5 * Math.PI; - var datasetStartAngle = opts.startAngle; - var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); - var startAngle = datasetStartAngle + (circumference * visibleCount); - var endAngle = startAngle + (arc.hidden ? 0 : circumference); - - var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); - - helpers.extend(arc, { - // Utility - _datasetIndex: me.index, - _index: index, - _scale: scale, - - // Desired view properties - _model: { - x: centerX, - y: centerY, - innerRadius: 0, - outerRadius: reset ? resetRadius : distance, - startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle, - endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle, - label: helpers.valueAtIndexOrDefault(labels, index, labels[index]) - } - }); - - // Apply border and fill style - me.removeHoverStyle(arc); - - arc.pivot(); - }, - - removeHoverStyle: function (arc) { - Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); - }, - - countVisibleElements: function () { - var dataset = this.getDataset(); - var meta = this.getMeta(); - var count = 0; - - helpers.each(meta.data, function (element, index) { - if (!isNaN(dataset.data[index]) && !element.hidden) { - count++; - } - }); - - return count; - }, - - calculateCircumference: function (value) { - var count = this.getMeta().count; - if (count > 0 && !isNaN(value)) { - return (2 * Math.PI) / count; - } - return 0; - } - }); - }; - - }, { "25": 25, "40": 40, "45": 45 }], 20: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('radar', { - scale: { - type: 'radialLinear' - }, - elements: { - line: { - tension: 0 // no bezier in radar - } - } - }); - - module.exports = function (Chart) { - - Chart.controllers.radar = Chart.DatasetController.extend({ - - datasetElementType: elements.Line, - - dataElementType: elements.Point, - - linkScales: helpers.noop, - - update: function (reset) { - var me = this; - var meta = me.getMeta(); - var line = meta.dataset; - var points = meta.data; - var custom = line.custom || {}; - var dataset = me.getDataset(); - var lineElementOptions = me.chart.options.elements.line; - var scale = me.chart.scale; - - // Compatibility: If the properties are defined with only the old name, use those values - if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { - dataset.lineTension = dataset.tension; - } - - helpers.extend(meta.dataset, { - // Utility - _datasetIndex: me.index, - _scale: scale, - // Data - _children: points, - _loop: true, - // Model - _model: { - // Appearance - tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension), - backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), - borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), - borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), - fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), - borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), - borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), - borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), - borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), - } - }); - - meta.dataset.pivot(); - - // Update Points - helpers.each(points, function (point, index) { - me.updateElement(point, index, reset); - }, me); - - // Update bezier control points - me.updateBezierControlPoints(); - }, - updateElement: function (point, index, reset) { - var me = this; - var custom = point.custom || {}; - var dataset = me.getDataset(); - var scale = me.chart.scale; - var pointElementOptions = me.chart.options.elements.point; - var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]); - - // Compatibility: If the properties are defined with only the old name, use those values - if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) { - dataset.pointRadius = dataset.radius; - } - if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) { - dataset.pointHitRadius = dataset.hitRadius; - } - - helpers.extend(point, { - // Utility - _datasetIndex: me.index, - _index: index, - _scale: scale, - - // Desired view properties - _model: { - x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales - y: reset ? scale.yCenter : pointPosition.y, - - // Appearance - tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension), - radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius), - backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor), - borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor), - borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth), - pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle), - - // Tooltip - hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius) - } - }); - - point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); - }, - updateBezierControlPoints: function () { - var chartArea = this.chart.chartArea; - var meta = this.getMeta(); - - helpers.each(meta.data, function (point, index) { - var model = point._model; - var controlPoints = helpers.splineCurve( - helpers.previousItem(meta.data, index, true)._model, - model, - helpers.nextItem(meta.data, index, true)._model, - model.tension - ); - - // Prevent the bezier going outside of the bounds of the graph - model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left); - model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top); - - model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left); - model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top); - - // Now pivot the point for animation - point.pivot(); - }); - }, - - setHoverStyle: function (point) { - // Point - var dataset = this.chart.data.datasets[point._datasetIndex]; - var custom = point.custom || {}; - var index = point._index; - var model = point._model; - - model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); - model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); - model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor)); - model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth); - }, - - removeHoverStyle: function (point) { - var dataset = this.chart.data.datasets[point._datasetIndex]; - var custom = point.custom || {}; - var index = point._index; - var model = point._model; - var pointElementOptions = this.chart.options.elements.point; - - model.radius = custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius); - model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor); - model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor); - model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth); - } - }); - }; - - }, { "25": 25, "40": 40, "45": 45 }], 21: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - - defaults._set('scatter', { - hover: { - mode: 'single' - }, - - scales: { - xAxes: [{ - id: 'x-axis-1', // need an ID so datasets can reference the scale - type: 'linear', // scatter should not use a category axis - position: 'bottom' - }], - yAxes: [{ - id: 'y-axis-1', - type: 'linear', - position: 'left' - }] - }, - - showLines: false, - - tooltips: { - callbacks: { - title: function () { - return ''; // doesn't make sense for scatter since data are formatted as a point - }, - label: function (item) { - return '(' + item.xLabel + ', ' + item.yLabel + ')'; - } - } - } - }); - - module.exports = function (Chart) { - - // Scatter charts use line controllers - Chart.controllers.scatter = Chart.controllers.line; - - }; - - }, { "25": 25 }], 22: [function (require, module, exports) { - /* global window: false */ - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - - defaults._set('global', { - animation: { - duration: 1000, - easing: 'easeOutQuart', - onProgress: helpers.noop, - onComplete: helpers.noop - } - }); - - module.exports = function (Chart) { - - Chart.Animation = Element.extend({ - chart: null, // the animation associated chart instance - currentStep: 0, // the current animation step - numSteps: 60, // default number of steps - easing: '', // the easing to use for this animation - render: null, // render function used by the animation service - - onAnimationProgress: null, // user specified callback to fire on each step of the animation - onAnimationComplete: null, // user specified callback to fire when the animation finishes - }); - - Chart.animationService = { - frameDuration: 17, - animations: [], - dropFrames: 0, - request: null, - - /** - * @param {Chart} chart - The chart to animate. - * @param {Chart.Animation} animation - The animation that we will animate. - * @param {Number} duration - The animation duration in ms. - * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions - */ - addAnimation: function (chart, animation, duration, lazy) { - var animations = this.animations; - var i, ilen; - - animation.chart = chart; - - if (!lazy) { - chart.animating = true; - } - - for (i = 0, ilen = animations.length; i < ilen; ++i) { - if (animations[i].chart === chart) { - animations[i] = animation; - return; - } - } - - animations.push(animation); - - // If there are no animations queued, manually kickstart a digest, for lack of a better word - if (animations.length === 1) { - this.requestAnimationFrame(); - } - }, - - cancelAnimation: function (chart) { - var index = helpers.findIndex(this.animations, function (animation) { - return animation.chart === chart; - }); - - if (index !== -1) { - this.animations.splice(index, 1); - chart.animating = false; - } - }, - - requestAnimationFrame: function () { - var me = this; - if (me.request === null) { - // Skip animation frame requests until the active one is executed. - // This can happen when processing mouse events, e.g. 'mousemove' - // and 'mouseout' events will trigger multiple renders. - me.request = helpers.requestAnimFrame.call(window, function () { - me.request = null; - me.startDigest(); - }); - } - }, - - /** - * @private - */ - startDigest: function () { - var me = this; - var startTime = Date.now(); - var framesToDrop = 0; - - if (me.dropFrames > 1) { - framesToDrop = Math.floor(me.dropFrames); - me.dropFrames = me.dropFrames % 1; - } - - me.advance(1 + framesToDrop); - - var endTime = Date.now(); - - me.dropFrames += (endTime - startTime) / me.frameDuration; - - // Do we have more stuff to animate? - if (me.animations.length > 0) { - me.requestAnimationFrame(); - } - }, - - /** - * @private - */ - advance: function (count) { - var animations = this.animations; - var animation, chart; - var i = 0; - - while (i < animations.length) { - animation = animations[i]; - chart = animation.chart; - - animation.currentStep = (animation.currentStep || 0) + count; - animation.currentStep = Math.min(animation.currentStep, animation.numSteps); - - helpers.callback(animation.render, [chart, animation], chart); - helpers.callback(animation.onAnimationProgress, [animation], chart); - - if (animation.currentStep >= animation.numSteps) { - helpers.callback(animation.onAnimationComplete, [animation], chart); - chart.animating = false; - animations.splice(i, 1); - } else { - ++i; - } - } - } - }; - - /** - * Provided for backward compatibility, use Chart.Animation instead - * @prop Chart.Animation#animationObject - * @deprecated since version 2.6.0 - * @todo remove at version 3 - */ - Object.defineProperty(Chart.Animation.prototype, 'animationObject', { - get: function () { - return this; - } - }); - - /** - * Provided for backward compatibility, use Chart.Animation#chart instead - * @prop Chart.Animation#chartInstance - * @deprecated since version 2.6.0 - * @todo remove at version 3 - */ - Object.defineProperty(Chart.Animation.prototype, 'chartInstance', { - get: function () { - return this.chart; - }, - set: function (value) { - this.chart = value; - } - }); - - }; - - }, { "25": 25, "26": 26, "45": 45 }], 23: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var helpers = require(45); - var Interaction = require(28); - var layouts = require(30); - var platform = require(48); - var plugins = require(31); - - module.exports = function (Chart) { - - // Create a dictionary of chart types, to allow for extension of existing types - Chart.types = {}; - - // Store a reference to each instance - allowing us to globally resize chart instances on window resize. - // Destroy method on the chart will remove the instance of the chart from this reference. - Chart.instances = {}; - - // Controllers available for dataset visualization eg. bar, line, slice, etc. - Chart.controllers = {}; - - /** - * Initializes the given config with global and chart default values. - */ - function initConfig(config) { - config = config || {}; - - // Do NOT use configMerge() for the data object because this method merges arrays - // and so would change references to labels and datasets, preventing data updates. - var data = config.data = config.data || {}; - data.datasets = data.datasets || []; - data.labels = data.labels || []; - - config.options = helpers.configMerge( - defaults.global, - defaults[config.type], - config.options || {}); - - return config; - } - - /** - * Updates the config of the chart - * @param chart {Chart} chart to update the options for - */ - function updateConfig(chart) { - var newOptions = chart.options; - - helpers.each(chart.scales, function (scale) { - layouts.removeBox(chart, scale); - }); - - newOptions = helpers.configMerge( - Chart.defaults.global, - Chart.defaults[chart.config.type], - newOptions); - - chart.options = chart.config.options = newOptions; - chart.ensureScalesHaveIDs(); - chart.buildOrUpdateScales(); - // Tooltip - chart.tooltip._options = newOptions.tooltips; - chart.tooltip.initialize(); - } - - function positionIsHorizontal(position) { - return position === 'top' || position === 'bottom'; - } - - helpers.extend(Chart.prototype, /** @lends Chart */ { - /** - * @private - */ - construct: function (item, config) { - var me = this; - - config = initConfig(config); - - var context = platform.acquireContext(item, config); - var canvas = context && context.canvas; - var height = canvas && canvas.height; - var width = canvas && canvas.width; - - me.id = helpers.uid(); - me.ctx = context; - me.canvas = canvas; - me.config = config; - me.width = width; - me.height = height; - me.aspectRatio = height ? width / height : null; - me.options = config.options; - me._bufferedRender = false; - - /** - * Provided for backward compatibility, Chart and Chart.Controller have been merged, - * the "instance" still need to be defined since it might be called from plugins. - * @prop Chart#chart - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ - me.chart = me; - me.controller = me; // chart.chart.controller #inception - - // Add the chart instance to the global namespace - Chart.instances[me.id] = me; - - // Define alias to the config data: `chart.data === chart.config.data` - Object.defineProperty(me, 'data', { - get: function () { - return me.config.data; - }, - set: function (value) { - me.config.data = value; - } - }); - - if (!context || !canvas) { - // The given item is not a compatible context2d element, let's return before finalizing - // the chart initialization but after setting basic chart / controller properties that - // can help to figure out that the chart is not valid (e.g chart.canvas !== null); - // https://github.com/chartjs/Chart.js/issues/2807 - console.error("Failed to create chart: can't acquire context from the given item"); - return; - } - - me.initialize(); - me.update(); - }, - - /** - * @private - */ - initialize: function () { - var me = this; - - // Before init plugin notification - plugins.notify(me, 'beforeInit'); - - helpers.retinaScale(me, me.options.devicePixelRatio); - - me.bindEvents(); - - if (me.options.responsive) { - // Initial resize before chart draws (must be silent to preserve initial animations). - me.resize(true); - } - - // Make sure scales have IDs and are built before we build any controllers. - me.ensureScalesHaveIDs(); - me.buildOrUpdateScales(); - me.initToolTip(); - - // After init plugin notification - plugins.notify(me, 'afterInit'); - - return me; - }, - - clear: function () { - helpers.canvas.clear(this); - return this; - }, - - stop: function () { - // Stops any current animation loop occurring - Chart.animationService.cancelAnimation(this); - return this; - }, - - resize: function (silent) { - var me = this; - var options = me.options; - var canvas = me.canvas; - var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null; - - // the canvas render width and height will be casted to integers so make sure that - // the canvas display style uses the same integer values to avoid blurring effect. - - // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collased - var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas))); - var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas))); - - if (me.width === newWidth && me.height === newHeight) { - return; - } - - canvas.width = me.width = newWidth; - canvas.height = me.height = newHeight; - canvas.style.width = newWidth + 'px'; - canvas.style.height = newHeight + 'px'; - - helpers.retinaScale(me, options.devicePixelRatio); - - if (!silent) { - // Notify any plugins about the resize - var newSize = { width: newWidth, height: newHeight }; - plugins.notify(me, 'resize', [newSize]); - - // Notify of resize - if (me.options.onResize) { - me.options.onResize(me, newSize); - } - - me.stop(); - me.update(me.options.responsiveAnimationDuration); - } - }, - - ensureScalesHaveIDs: function () { - var options = this.options; - var scalesOptions = options.scales || {}; - var scaleOptions = options.scale; - - helpers.each(scalesOptions.xAxes, function (xAxisOptions, index) { - xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index); - }); - - helpers.each(scalesOptions.yAxes, function (yAxisOptions, index) { - yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index); - }); - - if (scaleOptions) { - scaleOptions.id = scaleOptions.id || 'scale'; - } - }, - - /** - * Builds a map of scale ID to scale object for future lookup. - */ - buildOrUpdateScales: function () { - var me = this; - var options = me.options; - var scales = me.scales || {}; - var items = []; - var updated = Object.keys(scales).reduce(function (obj, id) { - obj[id] = false; - return obj; - }, {}); - - if (options.scales) { - items = items.concat( - (options.scales.xAxes || []).map(function (xAxisOptions) { - return { options: xAxisOptions, dtype: 'category', dposition: 'bottom' }; - }), - (options.scales.yAxes || []).map(function (yAxisOptions) { - return { options: yAxisOptions, dtype: 'linear', dposition: 'left' }; - }) - ); - } - - if (options.scale) { - items.push({ - options: options.scale, - dtype: 'radialLinear', - isDefault: true, - dposition: 'chartArea' - }); - } - - helpers.each(items, function (item) { - var scaleOptions = item.options; - var id = scaleOptions.id; - var scaleType = helpers.valueOrDefault(scaleOptions.type, item.dtype); - - if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) { - scaleOptions.position = item.dposition; - } - - updated[id] = true; - var scale = null; - if (id in scales && scales[id].type === scaleType) { - scale = scales[id]; - scale.options = scaleOptions; - scale.ctx = me.ctx; - scale.chart = me; - } else { - var scaleClass = Chart.scaleService.getScaleConstructor(scaleType); - if (!scaleClass) { - return; - } - scale = new scaleClass({ - id: id, - type: scaleType, - options: scaleOptions, - ctx: me.ctx, - chart: me - }); - scales[scale.id] = scale; - } - - scale.mergeTicksOptions(); - - // TODO(SB): I think we should be able to remove this custom case (options.scale) - // and consider it as a regular scale part of the "scales"" map only! This would - // make the logic easier and remove some useless? custom code. - if (item.isDefault) { - me.scale = scale; - } - }); - // clear up discarded scales - helpers.each(updated, function (hasUpdated, id) { - if (!hasUpdated) { - delete scales[id]; - } - }); - - me.scales = scales; - - Chart.scaleService.addScalesToLayout(this); - }, - - buildOrUpdateControllers: function () { - var me = this; - var types = []; - var newControllers = []; - - helpers.each(me.data.datasets, function (dataset, datasetIndex) { - var meta = me.getDatasetMeta(datasetIndex); - var type = dataset.type || me.config.type; - - if (meta.type && meta.type !== type) { - me.destroyDatasetMeta(datasetIndex); - meta = me.getDatasetMeta(datasetIndex); - } - meta.type = type; - - types.push(meta.type); - - if (meta.controller) { - meta.controller.updateIndex(datasetIndex); - meta.controller.linkScales(); - } else { - var ControllerClass = Chart.controllers[meta.type]; - if (ControllerClass === undefined) { - throw new Error('"' + meta.type + '" is not a chart type.'); - } - - meta.controller = new ControllerClass(me, datasetIndex); - newControllers.push(meta.controller); - } - }, me); - - return newControllers; - }, - - /** - * Reset the elements of all datasets - * @private - */ - resetElements: function () { - var me = this; - helpers.each(me.data.datasets, function (dataset, datasetIndex) { - me.getDatasetMeta(datasetIndex).controller.reset(); - }, me); - }, - - /** - * Resets the chart back to it's state before the initial animation - */ - reset: function () { - this.resetElements(); - this.tooltip.initialize(); - }, - - update: function (config) { - var me = this; - - if (!config || typeof config !== 'object') { - // backwards compatibility - config = { - duration: config, - lazy: arguments[1] - }; - } - - updateConfig(me); - - // plugins options references might have change, let's invalidate the cache - // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167 - plugins._invalidate(me); - - if (plugins.notify(me, 'beforeUpdate') === false) { - return; - } - - // In case the entire data object changed - me.tooltip._data = me.data; - - // Make sure dataset controllers are updated and new controllers are reset - var newControllers = me.buildOrUpdateControllers(); - - // Make sure all dataset controllers have correct meta data counts - helpers.each(me.data.datasets, function (dataset, datasetIndex) { - me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); - }, me); - - me.updateLayout(); - - // Can only reset the new controllers after the scales have been updated - if (me.options.animation && me.options.animation.duration) { - helpers.each(newControllers, function (controller) { - controller.reset(); - }); - } - - me.updateDatasets(); - - // Need to reset tooltip in case it is displayed with elements that are removed - // after update. - me.tooltip.initialize(); - - // Last active contains items that were previously in the tooltip. - // When we reset the tooltip, we need to clear it - me.lastActive = []; - - // Do this before render so that any plugins that need final scale updates can use it - plugins.notify(me, 'afterUpdate'); - - if (me._bufferedRender) { - me._bufferedRequest = { - duration: config.duration, - easing: config.easing, - lazy: config.lazy - }; - } else { - me.render(config); - } - }, - - /** - * Updates the chart layout unless a plugin returns `false` to the `beforeLayout` - * hook, in which case, plugins will not be called on `afterLayout`. - * @private - */ - updateLayout: function () { - var me = this; - - if (plugins.notify(me, 'beforeLayout') === false) { - return; - } - - layouts.update(this, this.width, this.height); - - /** - * Provided for backward compatibility, use `afterLayout` instead. - * @method IPlugin#afterScaleUpdate - * @deprecated since version 2.5.0 - * @todo remove at version 3 - * @private - */ - plugins.notify(me, 'afterScaleUpdate'); - plugins.notify(me, 'afterLayout'); - }, - - /** - * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate` - * hook, in which case, plugins will not be called on `afterDatasetsUpdate`. - * @private - */ - updateDatasets: function () { - var me = this; - - if (plugins.notify(me, 'beforeDatasetsUpdate') === false) { - return; - } - - for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { - me.updateDataset(i); - } - - plugins.notify(me, 'afterDatasetsUpdate'); - }, - - /** - * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate` - * hook, in which case, plugins will not be called on `afterDatasetUpdate`. - * @private - */ - updateDataset: function (index) { - var me = this; - var meta = me.getDatasetMeta(index); - var args = { - meta: meta, - index: index - }; - - if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) { - return; - } - - meta.controller.update(); - - plugins.notify(me, 'afterDatasetUpdate', [args]); - }, - - render: function (config) { - var me = this; - - if (!config || typeof config !== 'object') { - // backwards compatibility - config = { - duration: config, - lazy: arguments[1] - }; - } - - var duration = config.duration; - var lazy = config.lazy; - - if (plugins.notify(me, 'beforeRender') === false) { - return; - } - - var animationOptions = me.options.animation; - var onComplete = function (animation) { - plugins.notify(me, 'afterRender'); - helpers.callback(animationOptions && animationOptions.onComplete, [animation], me); - }; - - if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) { - var animation = new Chart.Animation({ - numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps - easing: config.easing || animationOptions.easing, - - render: function (chart, animationObject) { - var easingFunction = helpers.easing.effects[animationObject.easing]; - var currentStep = animationObject.currentStep; - var stepDecimal = currentStep / animationObject.numSteps; - - chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep); - }, - - onAnimationProgress: animationOptions.onProgress, - onAnimationComplete: onComplete - }); - - Chart.animationService.addAnimation(me, animation, duration, lazy); - } else { - me.draw(); - - // See https://github.com/chartjs/Chart.js/issues/3781 - onComplete(new Chart.Animation({ numSteps: 0, chart: me })); - } - - return me; - }, - - draw: function (easingValue) { - var me = this; - - me.clear(); - - if (helpers.isNullOrUndef(easingValue)) { - easingValue = 1; - } - - me.transition(easingValue); - - if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) { - return; - } - - // Draw all the scales - helpers.each(me.boxes, function (box) { - box.draw(me.chartArea); - }, me); - - if (me.scale) { - me.scale.draw(); - } - - me.drawDatasets(easingValue); - me._drawTooltip(easingValue); - - plugins.notify(me, 'afterDraw', [easingValue]); - }, - - /** - * @private - */ - transition: function (easingValue) { - var me = this; - - for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) { - if (me.isDatasetVisible(i)) { - me.getDatasetMeta(i).controller.transition(easingValue); - } - } - - me.tooltip.transition(easingValue); - }, - - /** - * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw` - * hook, in which case, plugins will not be called on `afterDatasetsDraw`. - * @private - */ - drawDatasets: function (easingValue) { - var me = this; - - if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) { - return; - } - - // Draw datasets reversed to support proper line stacking - for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) { - if (me.isDatasetVisible(i)) { - me.drawDataset(i, easingValue); - } - } - - plugins.notify(me, 'afterDatasetsDraw', [easingValue]); - }, - - /** - * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw` - * hook, in which case, plugins will not be called on `afterDatasetDraw`. - * @private - */ - drawDataset: function (index, easingValue) { - var me = this; - var meta = me.getDatasetMeta(index); - var args = { - meta: meta, - index: index, - easingValue: easingValue - }; - - if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) { - return; - } - - meta.controller.draw(easingValue); - - plugins.notify(me, 'afterDatasetDraw', [args]); - }, - - /** - * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw` - * hook, in which case, plugins will not be called on `afterTooltipDraw`. - * @private - */ - _drawTooltip: function (easingValue) { - var me = this; - var tooltip = me.tooltip; - var args = { - tooltip: tooltip, - easingValue: easingValue - }; - - if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) { - return; - } - - tooltip.draw(); - - plugins.notify(me, 'afterTooltipDraw', [args]); - }, - - // Get the single element that was clicked on - // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw - getElementAtEvent: function (e) { - return Interaction.modes.single(this, e); - }, - - getElementsAtEvent: function (e) { - return Interaction.modes.label(this, e, { intersect: true }); - }, - - getElementsAtXAxis: function (e) { - return Interaction.modes['x-axis'](this, e, { intersect: true }); - }, - - getElementsAtEventForMode: function (e, mode, options) { - var method = Interaction.modes[mode]; - if (typeof method === 'function') { - return method(this, e, options); - } - - return []; - }, - - getDatasetAtEvent: function (e) { - return Interaction.modes.dataset(this, e, { intersect: true }); - }, - - getDatasetMeta: function (datasetIndex) { - var me = this; - var dataset = me.data.datasets[datasetIndex]; - if (!dataset._meta) { - dataset._meta = {}; - } - - var meta = dataset._meta[me.id]; - if (!meta) { - meta = dataset._meta[me.id] = { - type: null, - data: [], - dataset: null, - controller: null, - hidden: null, // See isDatasetVisible() comment - xAxisID: null, - yAxisID: null - }; - } - - return meta; - }, - - getVisibleDatasetCount: function () { - var count = 0; - for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - if (this.isDatasetVisible(i)) { - count++; - } - } - return count; - }, - - isDatasetVisible: function (datasetIndex) { - var meta = this.getDatasetMeta(datasetIndex); - - // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false, - // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned. - return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden; - }, - - generateLegend: function () { - return this.options.legendCallback(this); - }, - - /** - * @private - */ - destroyDatasetMeta: function (datasetIndex) { - var id = this.id; - var dataset = this.data.datasets[datasetIndex]; - var meta = dataset._meta && dataset._meta[id]; - - if (meta) { - meta.controller.destroy(); - delete dataset._meta[id]; - } - }, - - destroy: function () { - var me = this; - var canvas = me.canvas; - var i, ilen; - - me.stop(); - - // dataset controllers need to cleanup associated data - for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { - me.destroyDatasetMeta(i); - } - - if (canvas) { - me.unbindEvents(); - helpers.canvas.clear(me); - platform.releaseContext(me.ctx); - me.canvas = null; - me.ctx = null; - } - - plugins.notify(me, 'destroy'); - - delete Chart.instances[me.id]; - }, - - toBase64Image: function () { - return this.canvas.toDataURL.apply(this.canvas, arguments); - }, - - initToolTip: function () { - var me = this; - me.tooltip = new Chart.Tooltip({ - _chart: me, - _chartInstance: me, // deprecated, backward compatibility - _data: me.data, - _options: me.options.tooltips - }, me); - }, - - /** - * @private - */ - bindEvents: function () { - var me = this; - var listeners = me._listeners = {}; - var listener = function () { - me.eventHandler.apply(me, arguments); - }; - - helpers.each(me.options.events, function (type) { - platform.addEventListener(me, type, listener); - listeners[type] = listener; - }); - - // Elements used to detect size change should not be injected for non responsive charts. - // See https://github.com/chartjs/Chart.js/issues/2210 - if (me.options.responsive) { - listener = function () { - me.resize(); - }; - - platform.addEventListener(me, 'resize', listener); - listeners.resize = listener; - } - }, - - /** - * @private - */ - unbindEvents: function () { - var me = this; - var listeners = me._listeners; - if (!listeners) { - return; - } - - delete me._listeners; - helpers.each(listeners, function (listener, type) { - platform.removeEventListener(me, type, listener); - }); - }, - - updateHoverStyle: function (elements, mode, enabled) { - var method = enabled ? 'setHoverStyle' : 'removeHoverStyle'; - var element, i, ilen; - - for (i = 0, ilen = elements.length; i < ilen; ++i) { - element = elements[i]; - if (element) { - this.getDatasetMeta(element._datasetIndex).controller[method](element); - } - } - }, - - /** - * @private - */ - eventHandler: function (e) { - var me = this; - var tooltip = me.tooltip; - - if (plugins.notify(me, 'beforeEvent', [e]) === false) { - return; - } - - // Buffer any update calls so that renders do not occur - me._bufferedRender = true; - me._bufferedRequest = null; - - var changed = me.handleEvent(e); - // for smooth tooltip animations issue #4989 - // the tooltip should be the source of change - // Animation check workaround: - // tooltip._start will be null when tooltip isn't animating - if (tooltip) { - changed = tooltip._start - ? tooltip.handleEvent(e) - : changed | tooltip.handleEvent(e); - } - - plugins.notify(me, 'afterEvent', [e]); - - var bufferedRequest = me._bufferedRequest; - if (bufferedRequest) { - // If we have an update that was triggered, we need to do a normal render - me.render(bufferedRequest); - } else if (changed && !me.animating) { - // If entering, leaving, or changing elements, animate the change via pivot - me.stop(); - - // We only need to render at this point. Updating will cause scales to be - // recomputed generating flicker & using more memory than necessary. - me.render(me.options.hover.animationDuration, true); - } - - me._bufferedRender = false; - me._bufferedRequest = null; - - return me; - }, - - /** - * Handle an event - * @private - * @param {IEvent} event the event to handle - * @return {Boolean} true if the chart needs to re-render - */ - handleEvent: function (e) { - var me = this; - var options = me.options || {}; - var hoverOptions = options.hover; - var changed = false; - - me.lastActive = me.lastActive || []; - - // Find Active Elements for hover and tooltips - if (e.type === 'mouseout') { - me.active = []; - } else { - me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions); - } - - // Invoke onHover hook - // Need to call with native event here to not break backwards compatibility - helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me); - - if (e.type === 'mouseup' || e.type === 'click') { - if (options.onClick) { - // Use e.native here for backwards compatibility - options.onClick.call(me, e.native, me.active); - } - } - - // Remove styling for last active (even if it may still be active) - if (me.lastActive.length) { - me.updateHoverStyle(me.lastActive, hoverOptions.mode, false); - } - - // Built in hover styling - if (me.active.length && hoverOptions.mode) { - me.updateHoverStyle(me.active, hoverOptions.mode, true); - } - - changed = !helpers.arrayEquals(me.active, me.lastActive); - - // Remember Last Actives - me.lastActive = me.active; - - return changed; - } - }); - - /** - * Provided for backward compatibility, use Chart instead. - * @class Chart.Controller - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ - Chart.Controller = Chart; - }; - - }, { "25": 25, "28": 28, "30": 30, "31": 31, "45": 45, "48": 48 }], 24: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - - module.exports = function (Chart) { - - var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; - - /** - * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice', - * 'unshift') and notify the listener AFTER the array has been altered. Listeners are - * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments. - */ - function listenArrayEvents(array, listener) { - if (array._chartjs) { - array._chartjs.listeners.push(listener); - return; - } - - Object.defineProperty(array, '_chartjs', { - configurable: true, - enumerable: false, - value: { - listeners: [listener] - } - }); - - arrayEvents.forEach(function (key) { - var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1); - var base = array[key]; - - Object.defineProperty(array, key, { - configurable: true, - enumerable: false, - value: function () { - var args = Array.prototype.slice.call(arguments); - var res = base.apply(this, args); - - helpers.each(array._chartjs.listeners, function (object) { - if (typeof object[method] === 'function') { - object[method].apply(object, args); - } - }); - - return res; - } - }); - }); - } - - /** - * Removes the given array event listener and cleanup extra attached properties (such as - * the _chartjs stub and overridden methods) if array doesn't have any more listeners. - */ - function unlistenArrayEvents(array, listener) { - var stub = array._chartjs; - if (!stub) { - return; - } - - var listeners = stub.listeners; - var index = listeners.indexOf(listener); - if (index !== -1) { - listeners.splice(index, 1); - } - - if (listeners.length > 0) { - return; - } - - arrayEvents.forEach(function (key) { - delete array[key]; - }); - - delete array._chartjs; - } - - // Base class for all dataset controllers (line, bar, etc) - Chart.DatasetController = function (chart, datasetIndex) { - this.initialize(chart, datasetIndex); - }; - - helpers.extend(Chart.DatasetController.prototype, { - - /** - * Element type used to generate a meta dataset (e.g. Chart.element.Line). - * @type {Chart.core.element} - */ - datasetElementType: null, - - /** - * Element type used to generate a meta data (e.g. Chart.element.Point). - * @type {Chart.core.element} - */ - dataElementType: null, - - initialize: function (chart, datasetIndex) { - var me = this; - me.chart = chart; - me.index = datasetIndex; - me.linkScales(); - me.addElements(); - }, - - updateIndex: function (datasetIndex) { - this.index = datasetIndex; - }, - - linkScales: function () { - var me = this; - var meta = me.getMeta(); - var dataset = me.getDataset(); - - if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) { - meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id; - } - if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) { - meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id; - } - }, - - getDataset: function () { - return this.chart.data.datasets[this.index]; - }, - - getMeta: function () { - return this.chart.getDatasetMeta(this.index); - }, - - getScaleForId: function (scaleID) { - return this.chart.scales[scaleID]; - }, - - reset: function () { - this.update(true); - }, - - /** - * @private - */ - destroy: function () { - if (this._data) { - unlistenArrayEvents(this._data, this); - } - }, - - createMetaDataset: function () { - var me = this; - var type = me.datasetElementType; - return type && new type({ - _chart: me.chart, - _datasetIndex: me.index - }); - }, - - createMetaData: function (index) { - var me = this; - var type = me.dataElementType; - return type && new type({ - _chart: me.chart, - _datasetIndex: me.index, - _index: index - }); - }, - - addElements: function () { - var me = this; - var meta = me.getMeta(); - var data = me.getDataset().data || []; - var metaData = meta.data; - var i, ilen; - - for (i = 0, ilen = data.length; i < ilen; ++i) { - metaData[i] = metaData[i] || me.createMetaData(i); - } - - meta.dataset = meta.dataset || me.createMetaDataset(); - }, - - addElementAndReset: function (index) { - var element = this.createMetaData(index); - this.getMeta().data.splice(index, 0, element); - this.updateElement(element, index, true); - }, - - buildOrUpdateElements: function () { - var me = this; - var dataset = me.getDataset(); - var data = dataset.data || (dataset.data = []); - - // In order to correctly handle data addition/deletion animation (an thus simulate - // real-time charts), we need to monitor these data modifications and synchronize - // the internal meta data accordingly. - if (me._data !== data) { - if (me._data) { - // This case happens when the user replaced the data array instance. - unlistenArrayEvents(me._data, me); - } - - listenArrayEvents(data, me); - me._data = data; - } - - // Re-sync meta data in case the user replaced the data array or if we missed - // any updates and so make sure that we handle number of datapoints changing. - me.resyncElements(); - }, - - update: helpers.noop, - - transition: function (easingValue) { - var meta = this.getMeta(); - var elements = meta.data || []; - var ilen = elements.length; - var i = 0; - - for (; i < ilen; ++i) { - elements[i].transition(easingValue); - } - - if (meta.dataset) { - meta.dataset.transition(easingValue); - } - }, - - draw: function () { - var meta = this.getMeta(); - var elements = meta.data || []; - var ilen = elements.length; - var i = 0; - - if (meta.dataset) { - meta.dataset.draw(); - } - - for (; i < ilen; ++i) { - elements[i].draw(); - } - }, - - removeHoverStyle: function (element, elementOpts) { - var dataset = this.chart.data.datasets[element._datasetIndex]; - var index = element._index; - var custom = element.custom || {}; - var valueOrDefault = helpers.valueAtIndexOrDefault; - var model = element._model; - - model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor); - model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor); - model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth); - }, - - setHoverStyle: function (element) { - var dataset = this.chart.data.datasets[element._datasetIndex]; - var index = element._index; - var custom = element.custom || {}; - var valueOrDefault = helpers.valueAtIndexOrDefault; - var getHoverColor = helpers.getHoverColor; - var model = element._model; - - model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor)); - model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor)); - model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); - }, - - /** - * @private - */ - resyncElements: function () { - var me = this; - var meta = me.getMeta(); - var data = me.getDataset().data; - var numMeta = meta.data.length; - var numData = data.length; - - if (numData < numMeta) { - meta.data.splice(numData, numMeta - numData); - } else if (numData > numMeta) { - me.insertElements(numMeta, numData - numMeta); - } - }, - - /** - * @private - */ - insertElements: function (start, count) { - for (var i = 0; i < count; ++i) { - this.addElementAndReset(start + i); - } - }, - - /** - * @private - */ - onDataPush: function () { - this.insertElements(this.getDataset().data.length - 1, arguments.length); - }, - - /** - * @private - */ - onDataPop: function () { - this.getMeta().data.pop(); - }, - - /** - * @private - */ - onDataShift: function () { - this.getMeta().data.shift(); - }, - - /** - * @private - */ - onDataSplice: function (start, count) { - this.getMeta().data.splice(start, count); - this.insertElements(start, arguments.length - 2); - }, - - /** - * @private - */ - onDataUnshift: function () { - this.insertElements(0, arguments.length); - } - }); - - Chart.DatasetController.extend = helpers.inherits; - }; - - }, { "45": 45 }], 25: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - - module.exports = { - /** - * @private - */ - _set: function (scope, values) { - return helpers.merge(this[scope] || (this[scope] = {}), values); - } - }; - - }, { "45": 45 }], 26: [function (require, module, exports) { - 'use strict'; - - var color = require(2); - var helpers = require(45); - - function interpolate(start, view, model, ease) { - var keys = Object.keys(model); - var i, ilen, key, actual, origin, target, type, c0, c1; - - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - - target = model[key]; - - // if a value is added to the model after pivot() has been called, the view - // doesn't contain it, so let's initialize the view to the target value. - if (!view.hasOwnProperty(key)) { - view[key] = target; - } - - actual = view[key]; - - if (actual === target || key[0] === '_') { - continue; - } - - if (!start.hasOwnProperty(key)) { - start[key] = actual; - } - - origin = start[key]; - - type = typeof target; - - if (type === typeof origin) { - if (type === 'string') { - c0 = color(origin); - if (c0.valid) { - c1 = color(target); - if (c1.valid) { - view[key] = c1.mix(c0, ease).rgbString(); - continue; - } - } - } else if (type === 'number' && isFinite(origin) && isFinite(target)) { - view[key] = origin + (target - origin) * ease; - continue; - } - } - - view[key] = target; - } - } - - var Element = function (configuration) { - helpers.extend(this, configuration); - this.initialize.apply(this, arguments); - }; - - helpers.extend(Element.prototype, { - - initialize: function () { - this.hidden = false; - }, - - pivot: function () { - var me = this; - if (!me._view) { - me._view = helpers.clone(me._model); - } - me._start = {}; - return me; - }, - - transition: function (ease) { - var me = this; - var model = me._model; - var start = me._start; - var view = me._view; - - // No animation -> No Transition - if (!model || ease === 1) { - me._view = model; - me._start = null; - return me; - } - - if (!view) { - view = me._view = {}; - } - - if (!start) { - start = me._start = {}; - } - - interpolate(start, view, model, ease); - - return me; - }, - - tooltipPosition: function () { - return { - x: this._model.x, - y: this._model.y - }; - }, - - hasValue: function () { - return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y); - } - }); - - Element.extend = helpers.inherits; - - module.exports = Element; - - }, { "2": 2, "45": 45 }], 27: [function (require, module, exports) { - /* global window: false */ - /* global document: false */ - 'use strict'; - - var color = require(2); - var defaults = require(25); - var helpers = require(45); - - module.exports = function (Chart) { - - // -- Basic js utility methods - - helpers.configMerge = function (/* objects ... */) { - return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), { - merger: function (key, target, source, options) { - var tval = target[key] || {}; - var sval = source[key]; - - if (key === 'scales') { - // scale config merging is complex. Add our own function here for that - target[key] = helpers.scaleMerge(tval, sval); - } else if (key === 'scale') { - // used in polar area & radar charts since there is only one scale - target[key] = helpers.merge(tval, [Chart.scaleService.getScaleDefaults(sval.type), sval]); - } else { - helpers._merger(key, target, source, options); - } - } - }); - }; - - helpers.scaleMerge = function (/* objects ... */) { - return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), { - merger: function (key, target, source, options) { - if (key === 'xAxes' || key === 'yAxes') { - var slen = source[key].length; - var i, type, scale; - - if (!target[key]) { - target[key] = []; - } - - for (i = 0; i < slen; ++i) { - scale = source[key][i]; - type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear'); - - if (i >= target[key].length) { - target[key].push({}); - } - - if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) { - // new/untyped scale or type changed: let's apply the new defaults - // then merge source scale to correctly overwrite the defaults. - helpers.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]); - } else { - // scales type are the same - helpers.merge(target[key][i], scale); - } - } - } else { - helpers._merger(key, target, source, options); - } - } - }); - }; - - helpers.where = function (collection, filterCallback) { - if (helpers.isArray(collection) && Array.prototype.filter) { - return collection.filter(filterCallback); - } - var filtered = []; - - helpers.each(collection, function (item) { - if (filterCallback(item)) { - filtered.push(item); - } - }); - - return filtered; - }; - helpers.findIndex = Array.prototype.findIndex ? - function (array, callback, scope) { - return array.findIndex(callback, scope); - } : - function (array, callback, scope) { - scope = scope === undefined ? array : scope; - for (var i = 0, ilen = array.length; i < ilen; ++i) { - if (callback.call(scope, array[i], i, array)) { - return i; - } - } - return -1; - }; - helpers.findNextWhere = function (arrayToSearch, filterCallback, startIndex) { - // Default to start of the array - if (helpers.isNullOrUndef(startIndex)) { - startIndex = -1; - } - for (var i = startIndex + 1; i < arrayToSearch.length; i++) { - var currentItem = arrayToSearch[i]; - if (filterCallback(currentItem)) { - return currentItem; - } - } - }; - helpers.findPreviousWhere = function (arrayToSearch, filterCallback, startIndex) { - // Default to end of the array - if (helpers.isNullOrUndef(startIndex)) { - startIndex = arrayToSearch.length; - } - for (var i = startIndex - 1; i >= 0; i--) { - var currentItem = arrayToSearch[i]; - if (filterCallback(currentItem)) { - return currentItem; - } - } - }; - - // -- Math methods - helpers.isNumber = function (n) { - return !isNaN(parseFloat(n)) && isFinite(n); - }; - helpers.almostEquals = function (x, y, epsilon) { - return Math.abs(x - y) < epsilon; - }; - helpers.almostWhole = function (x, epsilon) { - var rounded = Math.round(x); - return (((rounded - epsilon) < x) && ((rounded + epsilon) > x)); - }; - helpers.max = function (array) { - return array.reduce(function (max, value) { - if (!isNaN(value)) { - return Math.max(max, value); - } - return max; - }, Number.NEGATIVE_INFINITY); - }; - helpers.min = function (array) { - return array.reduce(function (min, value) { - if (!isNaN(value)) { - return Math.min(min, value); - } - return min; - }, Number.POSITIVE_INFINITY); - }; - helpers.sign = Math.sign ? - function (x) { - return Math.sign(x); - } : - function (x) { - x = +x; // convert to a number - if (x === 0 || isNaN(x)) { - return x; - } - return x > 0 ? 1 : -1; - }; - helpers.log10 = Math.log10 ? - function (x) { - return Math.log10(x); - } : - function (x) { - var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10. - // Check for whole powers of 10, - // which due to floating point rounding error should be corrected. - var powerOf10 = Math.round(exponent); - var isPowerOf10 = x === Math.pow(10, powerOf10); - - return isPowerOf10 ? powerOf10 : exponent; - }; - helpers.toRadians = function (degrees) { - return degrees * (Math.PI / 180); - }; - helpers.toDegrees = function (radians) { - return radians * (180 / Math.PI); - }; - // Gets the angle from vertical upright to the point about a centre. - helpers.getAngleFromPoint = function (centrePoint, anglePoint) { - var distanceFromXCenter = anglePoint.x - centrePoint.x; - var distanceFromYCenter = anglePoint.y - centrePoint.y; - var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); - - var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); - - if (angle < (-0.5 * Math.PI)) { - angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2] - } - - return { - angle: angle, - distance: radialDistanceFromCenter - }; - }; - helpers.distanceBetweenPoints = function (pt1, pt2) { - return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); - }; - helpers.aliasPixel = function (pixelWidth) { - return (pixelWidth % 2 === 0) ? 0 : 0.5; - }; - helpers.splineCurve = function (firstPoint, middlePoint, afterPoint, t) { - // Props to Rob Spencer at scaled innovation for his post on splining between points - // http://scaledinnovation.com/analytics/splines/aboutSplines.html - - // This function must also respect "skipped" points - - var previous = firstPoint.skip ? middlePoint : firstPoint; - var current = middlePoint; - var next = afterPoint.skip ? middlePoint : afterPoint; - - var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)); - var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)); - - var s01 = d01 / (d01 + d12); - var s12 = d12 / (d01 + d12); - - // If all points are the same, s01 & s02 will be inf - s01 = isNaN(s01) ? 0 : s01; - s12 = isNaN(s12) ? 0 : s12; - - var fa = t * s01; // scaling factor for triangle Ta - var fb = t * s12; - - return { - previous: { - x: current.x - fa * (next.x - previous.x), - y: current.y - fa * (next.y - previous.y) - }, - next: { - x: current.x + fb * (next.x - previous.x), - y: current.y + fb * (next.y - previous.y) - } - }; - }; - helpers.EPSILON = Number.EPSILON || 1e-14; - helpers.splineCurveMonotone = function (points) { - // This function calculates Bzier control points in a similar way than |splineCurve|, - // but preserves monotonicity of the provided data and ensures no local extremums are added - // between the dataset discrete points due to the interpolation. - // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation - - var pointsWithTangents = (points || []).map(function (point) { - return { - model: point._model, - deltaK: 0, - mK: 0 - }; - }); - - // Calculate slopes (deltaK) and initialize tangents (mK) - var pointsLen = pointsWithTangents.length; - var i, pointBefore, pointCurrent, pointAfter; - for (i = 0; i < pointsLen; ++i) { - pointCurrent = pointsWithTangents[i]; - if (pointCurrent.model.skip) { - continue; - } - - pointBefore = i > 0 ? pointsWithTangents[i - 1] : null; - pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null; - if (pointAfter && !pointAfter.model.skip) { - var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x); - - // In the case of two points that appear at the same x pixel, slopeDeltaX is 0 - pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0; - } - - if (!pointBefore || pointBefore.model.skip) { - pointCurrent.mK = pointCurrent.deltaK; - } else if (!pointAfter || pointAfter.model.skip) { - pointCurrent.mK = pointBefore.deltaK; - } else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) { - pointCurrent.mK = 0; - } else { - pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2; - } - } - - // Adjust tangents to ensure monotonic properties - var alphaK, betaK, tauK, squaredMagnitude; - for (i = 0; i < pointsLen - 1; ++i) { - pointCurrent = pointsWithTangents[i]; - pointAfter = pointsWithTangents[i + 1]; - if (pointCurrent.model.skip || pointAfter.model.skip) { - continue; - } - - if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) { - pointCurrent.mK = pointAfter.mK = 0; - continue; - } - - alphaK = pointCurrent.mK / pointCurrent.deltaK; - betaK = pointAfter.mK / pointCurrent.deltaK; - squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); - if (squaredMagnitude <= 9) { - continue; - } - - tauK = 3 / Math.sqrt(squaredMagnitude); - pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK; - pointAfter.mK = betaK * tauK * pointCurrent.deltaK; - } - - // Compute control points - var deltaX; - for (i = 0; i < pointsLen; ++i) { - pointCurrent = pointsWithTangents[i]; - if (pointCurrent.model.skip) { - continue; - } - - pointBefore = i > 0 ? pointsWithTangents[i - 1] : null; - pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null; - if (pointBefore && !pointBefore.model.skip) { - deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3; - pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX; - pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK; - } - if (pointAfter && !pointAfter.model.skip) { - deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3; - pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX; - pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK; - } - } - }; - helpers.nextItem = function (collection, index, loop) { - if (loop) { - return index >= collection.length - 1 ? collection[0] : collection[index + 1]; - } - return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1]; - }; - helpers.previousItem = function (collection, index, loop) { - if (loop) { - return index <= 0 ? collection[collection.length - 1] : collection[index - 1]; - } - return index <= 0 ? collection[0] : collection[index - 1]; - }; - // Implementation of the nice number algorithm used in determining where axis labels will go - helpers.niceNum = function (range, round) { - var exponent = Math.floor(helpers.log10(range)); - var fraction = range / Math.pow(10, exponent); - var niceFraction; - - if (round) { - if (fraction < 1.5) { - niceFraction = 1; - } else if (fraction < 3) { - niceFraction = 2; - } else if (fraction < 7) { - niceFraction = 5; - } else { - niceFraction = 10; - } - } else if (fraction <= 1.0) { - niceFraction = 1; - } else if (fraction <= 2) { - niceFraction = 2; - } else if (fraction <= 5) { - niceFraction = 5; - } else { - niceFraction = 10; - } - - return niceFraction * Math.pow(10, exponent); - }; - // Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ - helpers.requestAnimFrame = (function () { - if (typeof window === 'undefined') { - return function (callback) { - callback(); - }; - } - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { - return window.setTimeout(callback, 1000 / 60); - }; - } ()); - // -- DOM methods - helpers.getRelativePosition = function (evt, chart) { - var mouseX, mouseY; - var e = evt.originalEvent || evt; - var canvas = evt.currentTarget || evt.srcElement; - var boundingRect = canvas.getBoundingClientRect(); - - var touches = e.touches; - if (touches && touches.length > 0) { - mouseX = touches[0].clientX; - mouseY = touches[0].clientY; - - } else { - mouseX = e.clientX; - mouseY = e.clientY; - } - - // Scale mouse coordinates into canvas coordinates - // by following the pattern laid out by 'jerryj' in the comments of - // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ - var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left')); - var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top')); - var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right')); - var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom')); - var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight; - var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom; - - // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However - // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here - mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio); - mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio); - - return { - x: mouseX, - y: mouseY - }; - - }; - - // Private helper function to convert max-width/max-height values that may be percentages into a number - function parseMaxStyle(styleValue, node, parentProperty) { - var valueInPixels; - if (typeof styleValue === 'string') { - valueInPixels = parseInt(styleValue, 10); - - if (styleValue.indexOf('%') !== -1) { - // percentage * size in dimension - valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; - } - } else { - valueInPixels = styleValue; - } - - return valueInPixels; - } - - /** - * Returns if the given value contains an effective constraint. - * @private - */ - function isConstrainedValue(value) { - return value !== undefined && value !== null && value !== 'none'; - } - - // Private helper to get a constraint dimension - // @param domNode : the node to check the constraint on - // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight) - // @param percentageProperty : property of parent to use when calculating width as a percentage - // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser - function getConstraintDimension(domNode, maxStyle, percentageProperty) { - var view = document.defaultView; - var parentNode = domNode.parentNode; - var constrainedNode = view.getComputedStyle(domNode)[maxStyle]; - var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle]; - var hasCNode = isConstrainedValue(constrainedNode); - var hasCContainer = isConstrainedValue(constrainedContainer); - var infinity = Number.POSITIVE_INFINITY; - - if (hasCNode || hasCContainer) { - return Math.min( - hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity, - hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity); - } - - return 'none'; - } - // returns Number or undefined if no constraint - helpers.getConstraintWidth = function (domNode) { - return getConstraintDimension(domNode, 'max-width', 'clientWidth'); - }; - // returns Number or undefined if no constraint - helpers.getConstraintHeight = function (domNode) { - return getConstraintDimension(domNode, 'max-height', 'clientHeight'); - }; - helpers.getMaximumWidth = function (domNode) { - var container = domNode.parentNode; - if (!container) { - return domNode.clientWidth; - } - - var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10); - var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10); - var w = container.clientWidth - paddingLeft - paddingRight; - var cw = helpers.getConstraintWidth(domNode); - return isNaN(cw) ? w : Math.min(w, cw); - }; - helpers.getMaximumHeight = function (domNode) { - var container = domNode.parentNode; - if (!container) { - return domNode.clientHeight; - } - - var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10); - var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10); - var h = container.clientHeight - paddingTop - paddingBottom; - var ch = helpers.getConstraintHeight(domNode); - return isNaN(ch) ? h : Math.min(h, ch); - }; - helpers.getStyle = function (el, property) { - return el.currentStyle ? - el.currentStyle[property] : - document.defaultView.getComputedStyle(el, null).getPropertyValue(property); - }; - helpers.retinaScale = function (chart, forceRatio) { - var pixelRatio = chart.currentDevicePixelRatio = forceRatio || window.devicePixelRatio || 1; - if (pixelRatio === 1) { - return; - } - - var canvas = chart.canvas; - var height = chart.height; - var width = chart.width; - - canvas.height = height * pixelRatio; - canvas.width = width * pixelRatio; - chart.ctx.scale(pixelRatio, pixelRatio); - - // If no style has been set on the canvas, the render size is used as display size, - // making the chart visually bigger, so let's enforce it to the "correct" values. - // See https://github.com/chartjs/Chart.js/issues/3575 - if (!canvas.style.height && !canvas.style.width) { - canvas.style.height = height + 'px'; - canvas.style.width = width + 'px'; - } - }; - // -- Canvas methods - helpers.fontString = function (pixelSize, fontStyle, fontFamily) { - return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; - }; - helpers.longestText = function (ctx, font, arrayOfThings, cache) { - cache = cache || {}; - var data = cache.data = cache.data || {}; - var gc = cache.garbageCollect = cache.garbageCollect || []; - - if (cache.font !== font) { - data = cache.data = {}; - gc = cache.garbageCollect = []; - cache.font = font; - } - - ctx.font = font; - var longest = 0; - helpers.each(arrayOfThings, function (thing) { - // Undefined strings and arrays should not be measured - if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) { - longest = helpers.measureText(ctx, data, gc, longest, thing); - } else if (helpers.isArray(thing)) { - // if it is an array lets measure each element - // to do maybe simplify this function a bit so we can do this more recursively? - helpers.each(thing, function (nestedThing) { - // Undefined strings and arrays should not be measured - if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) { - longest = helpers.measureText(ctx, data, gc, longest, nestedThing); - } - }); - } - }); - - var gcLen = gc.length / 2; - if (gcLen > arrayOfThings.length) { - for (var i = 0; i < gcLen; i++) { - delete data[gc[i]]; - } - gc.splice(0, gcLen); - } - return longest; - }; - helpers.measureText = function (ctx, data, gc, longest, string) { - var textWidth = data[string]; - if (!textWidth) { - textWidth = data[string] = ctx.measureText(string).width; - gc.push(string); - } - if (textWidth > longest) { - longest = textWidth; - } - return longest; - }; - helpers.numberOfLabelLines = function (arrayOfThings) { - var numberOfLines = 1; - helpers.each(arrayOfThings, function (thing) { - if (helpers.isArray(thing)) { - if (thing.length > numberOfLines) { - numberOfLines = thing.length; - } - } - }); - return numberOfLines; - }; - - helpers.color = !color ? - function (value) { - console.error('Color.js not found!'); - return value; - } : - function (value) { - /* global CanvasGradient */ - if (value instanceof CanvasGradient) { - value = defaults.global.defaultColor; - } - - return color(value); - }; - - helpers.getHoverColor = function (colorValue) { - /* global CanvasPattern */ - return (colorValue instanceof CanvasPattern) ? - colorValue : - helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString(); - }; - }; - - }, { "2": 2, "25": 25, "45": 45 }], 28: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - - /** - * Helper function to get relative position for an event - * @param {Event|IEvent} event - The event to get the position for - * @param {Chart} chart - The chart - * @returns {Point} the event position - */ - function getRelativePosition(e, chart) { - if (e.native) { - return { - x: e.x, - y: e.y - }; - } - - return helpers.getRelativePosition(e, chart); - } - - /** - * Helper function to traverse all of the visible elements in the chart - * @param chart {chart} the chart - * @param handler {Function} the callback to execute for each visible item - */ - function parseVisibleItems(chart, handler) { - var datasets = chart.data.datasets; - var meta, i, j, ilen, jlen; - - for (i = 0, ilen = datasets.length; i < ilen; ++i) { - if (!chart.isDatasetVisible(i)) { - continue; - } - - meta = chart.getDatasetMeta(i); - for (j = 0, jlen = meta.data.length; j < jlen; ++j) { - var element = meta.data[j]; - if (!element._view.skip) { - handler(element); - } - } - } - } - - /** - * Helper function to get the items that intersect the event position - * @param items {ChartElement[]} elements to filter - * @param position {Point} the point to be nearest to - * @return {ChartElement[]} the nearest items - */ - function getIntersectItems(chart, position) { - var elements = []; - - parseVisibleItems(chart, function (element) { - if (element.inRange(position.x, position.y)) { - elements.push(element); - } - }); - - return elements; - } - - /** - * Helper function to get the items nearest to the event position considering all visible items in teh chart - * @param chart {Chart} the chart to look at elements from - * @param position {Point} the point to be nearest to - * @param intersect {Boolean} if true, only consider items that intersect the position - * @param distanceMetric {Function} function to provide the distance between points - * @return {ChartElement[]} the nearest items - */ - function getNearestItems(chart, position, intersect, distanceMetric) { - var minDistance = Number.POSITIVE_INFINITY; - var nearestItems = []; - - parseVisibleItems(chart, function (element) { - if (intersect && !element.inRange(position.x, position.y)) { - return; - } - - var center = element.getCenterPoint(); - var distance = distanceMetric(position, center); - - if (distance < minDistance) { - nearestItems = [element]; - minDistance = distance; - } else if (distance === minDistance) { - // Can have multiple items at the same distance in which case we sort by size - nearestItems.push(element); - } - }); - - return nearestItems; - } - - /** - * Get a distance metric function for two points based on the - * axis mode setting - * @param {String} axis the axis mode. x|y|xy - */ - function getDistanceMetricForAxis(axis) { - var useX = axis.indexOf('x') !== -1; - var useY = axis.indexOf('y') !== -1; - - return function (pt1, pt2) { - var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; - var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; - return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); - }; - } - - function indexMode(chart, e, options) { - var position = getRelativePosition(e, chart); - // Default axis for index mode is 'x' to match old behaviour - options.axis = options.axis || 'x'; - var distanceMetric = getDistanceMetricForAxis(options.axis); - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); - var elements = []; - - if (!items.length) { - return []; - } - - chart.data.datasets.forEach(function (dataset, datasetIndex) { - if (chart.isDatasetVisible(datasetIndex)) { - var meta = chart.getDatasetMeta(datasetIndex); - var element = meta.data[items[0]._index]; - - // don't count items that are skipped (null data) - if (element && !element._view.skip) { - elements.push(element); - } - } - }); - - return elements; - } - - /** - * @interface IInteractionOptions - */ - /** - * If true, only consider items that intersect the point - * @name IInterfaceOptions#boolean - * @type Boolean - */ - - /** - * Contains interaction related functions - * @namespace Chart.Interaction - */ - module.exports = { - // Helper function for different modes - modes: { - single: function (chart, e) { - var position = getRelativePosition(e, chart); - var elements = []; - - parseVisibleItems(chart, function (element) { - if (element.inRange(position.x, position.y)) { - elements.push(element); - return elements; - } - }); - - return elements.slice(0, 1); - }, - - /** - * @function Chart.Interaction.modes.label - * @deprecated since version 2.4.0 - * @todo remove at version 3 - * @private - */ - label: indexMode, - - /** - * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item - * @function Chart.Interaction.modes.index - * @since v2.4.0 - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use during interaction - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - index: indexMode, - - /** - * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect is false, we find the nearest item and return the items in that dataset - * @function Chart.Interaction.modes.dataset - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use during interaction - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - dataset: function (chart, e, options) { - var position = getRelativePosition(e, chart); - options.axis = options.axis || 'xy'; - var distanceMetric = getDistanceMetricForAxis(options.axis); - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); - - if (items.length > 0) { - items = chart.getDatasetMeta(items[0]._datasetIndex).data; - } - - return items; - }, - - /** - * @function Chart.Interaction.modes.x-axis - * @deprecated since version 2.4.0. Use index mode and intersect == true - * @todo remove at version 3 - * @private - */ - 'x-axis': function (chart, e) { - return indexMode(chart, e, { intersect: false }); - }, - - /** - * Point mode returns all elements that hit test based on the event position - * of the event - * @function Chart.Interaction.modes.intersect - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - point: function (chart, e) { - var position = getRelativePosition(e, chart); - return getIntersectItems(chart, position); - }, - - /** - * nearest mode returns the element closest to the point - * @function Chart.Interaction.modes.intersect - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - nearest: function (chart, e, options) { - var position = getRelativePosition(e, chart); - options.axis = options.axis || 'xy'; - var distanceMetric = getDistanceMetricForAxis(options.axis); - var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric); - - // We have multiple items at the same distance from the event. Now sort by smallest - if (nearestItems.length > 1) { - nearestItems.sort(function (a, b) { - var sizeA = a.getArea(); - var sizeB = b.getArea(); - var ret = sizeA - sizeB; - - if (ret === 0) { - // if equal sort by dataset index - ret = a._datasetIndex - b._datasetIndex; - } - - return ret; - }); - } - - // Return only 1 item - return nearestItems.slice(0, 1); - }, - - /** - * x mode returns the elements that hit-test at the current x coordinate - * @function Chart.Interaction.modes.x - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - x: function (chart, e, options) { - var position = getRelativePosition(e, chart); - var items = []; - var intersectsItem = false; - - parseVisibleItems(chart, function (element) { - if (element.inXRange(position.x)) { - items.push(element); - } - - if (element.inRange(position.x, position.y)) { - intersectsItem = true; - } - }); - - // If we want to trigger on an intersect and we don't have any items - // that intersect the position, return nothing - if (options.intersect && !intersectsItem) { - items = []; - } - return items; - }, - - /** - * y mode returns the elements that hit-test at the current y coordinate - * @function Chart.Interaction.modes.y - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - y: function (chart, e, options) { - var position = getRelativePosition(e, chart); - var items = []; - var intersectsItem = false; - - parseVisibleItems(chart, function (element) { - if (element.inYRange(position.y)) { - items.push(element); - } - - if (element.inRange(position.x, position.y)) { - intersectsItem = true; - } - }); - - // If we want to trigger on an intersect and we don't have any items - // that intersect the position, return nothing - if (options.intersect && !intersectsItem) { - items = []; - } - return items; - } - } - }; - - }, { "45": 45 }], 29: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - - defaults._set('global', { - responsive: true, - responsiveAnimationDuration: 0, - maintainAspectRatio: true, - events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], - hover: { - onHover: null, - mode: 'nearest', - intersect: true, - animationDuration: 400 - }, - onClick: null, - defaultColor: 'rgba(0,0,0,0.1)', - defaultFontColor: '#666', - defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - defaultFontSize: 12, - defaultFontStyle: 'normal', - showLines: true, - - // Element defaults defined in element extensions - elements: {}, - - // Layout options such as padding - layout: { - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } - } - }); - - module.exports = function () { - - // Occupy the global variable of Chart, and create a simple base class - var Chart = function (item, config) { - this.construct(item, config); - return this; - }; - - Chart.Chart = Chart; - - return Chart; - }; - - }, { "25": 25 }], 30: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - - function filterByPosition(array, position) { - return helpers.where(array, function (v) { - return v.position === position; - }); - } - - function sortByWeight(array, reverse) { - array.forEach(function (v, i) { - v._tmpIndex_ = i; - return v; - }); - array.sort(function (a, b) { - var v0 = reverse ? b : a; - var v1 = reverse ? a : b; - return v0.weight === v1.weight ? - v0._tmpIndex_ - v1._tmpIndex_ : - v0.weight - v1.weight; - }); - array.forEach(function (v) { - delete v._tmpIndex_; - }); - } - - /** - * @interface ILayoutItem - * @prop {String} position - The position of the item in the chart layout. Possible values are - * 'left', 'top', 'right', 'bottom', and 'chartArea' - * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area - * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down - * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom) - * @prop {Function} update - Takes two parameters: width and height. Returns size of item - * @prop {Function} getPadding - Returns an object with padding on the edges - * @prop {Number} width - Width of item. Must be valid after update() - * @prop {Number} height - Height of item. Must be valid after update() - * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update - * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update - * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update - * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update - */ - - // The layout service is very self explanatory. It's responsible for the layout within a chart. - // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need - // It is this service's responsibility of carrying out that layout. - module.exports = { - defaults: {}, - - /** - * Register a box to a chart. - * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title. - * @param {Chart} chart - the chart to use - * @param {ILayoutItem} item - the item to add to be layed out - */ - addBox: function (chart, item) { - if (!chart.boxes) { - chart.boxes = []; - } - - // initialize item with default values - item.fullWidth = item.fullWidth || false; - item.position = item.position || 'top'; - item.weight = item.weight || 0; - - chart.boxes.push(item); - }, - - /** - * Remove a layoutItem from a chart - * @param {Chart} chart - the chart to remove the box from - * @param {Object} layoutItem - the item to remove from the layout - */ - removeBox: function (chart, layoutItem) { - var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; - if (index !== -1) { - chart.boxes.splice(index, 1); - } - }, - - /** - * Sets (or updates) options on the given `item`. - * @param {Chart} chart - the chart in which the item lives (or will be added to) - * @param {Object} item - the item to configure with the given options - * @param {Object} options - the new item options. - */ - configure: function (chart, item, options) { - var props = ['fullWidth', 'position', 'weight']; - var ilen = props.length; - var i = 0; - var prop; - - for (; i < ilen; ++i) { - prop = props[i]; - if (options.hasOwnProperty(prop)) { - item[prop] = options[prop]; - } - } - }, - - /** - * Fits boxes of the given chart into the given size by having each box measure itself - * then running a fitting algorithm - * @param {Chart} chart - the chart - * @param {Number} width - the width to fit into - * @param {Number} height - the height to fit into - */ - update: function (chart, width, height) { - if (!chart) { - return; - } - - var layoutOptions = chart.options.layout || {}; - var padding = helpers.options.toPadding(layoutOptions.padding); - var leftPadding = padding.left; - var rightPadding = padding.right; - var topPadding = padding.top; - var bottomPadding = padding.bottom; - - var leftBoxes = filterByPosition(chart.boxes, 'left'); - var rightBoxes = filterByPosition(chart.boxes, 'right'); - var topBoxes = filterByPosition(chart.boxes, 'top'); - var bottomBoxes = filterByPosition(chart.boxes, 'bottom'); - var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea'); - - // Sort boxes by weight. A higher weight is further away from the chart area - sortByWeight(leftBoxes, true); - sortByWeight(rightBoxes, false); - sortByWeight(topBoxes, true); - sortByWeight(bottomBoxes, false); - - // Essentially we now have any number of boxes on each of the 4 sides. - // Our canvas looks like the following. - // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and - // B1 is the bottom axis - // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays - // These locations are single-box locations only, when trying to register a chartArea location that is already taken, - // an error will be thrown. - // - // |----------------------------------------------------| - // | T1 (Full Width) | - // |----------------------------------------------------| - // | | | T2 | | - // | |----|-------------------------------------|----| - // | | | C1 | | C2 | | - // | | |----| |----| | - // | | | | | - // | L1 | L2 | ChartArea (C0) | R1 | - // | | | | | - // | | |----| |----| | - // | | | C3 | | C4 | | - // | |----|-------------------------------------|----| - // | | | B1 | | - // |----------------------------------------------------| - // | B2 (Full Width) | - // |----------------------------------------------------| - // - // What we do to find the best sizing, we do the following - // 1. Determine the minimum size of the chart area. - // 2. Split the remaining width equally between each vertical axis - // 3. Split the remaining height equally between each horizontal axis - // 4. Give each layout the maximum size it can be. The layout will return it's minimum size - // 5. Adjust the sizes of each axis based on it's minimum reported size. - // 6. Refit each axis - // 7. Position each axis in the final location - // 8. Tell the chart the final location of the chart area - // 9. Tell any axes that overlay the chart area the positions of the chart area - - // Step 1 - var chartWidth = width - leftPadding - rightPadding; - var chartHeight = height - topPadding - bottomPadding; - var chartAreaWidth = chartWidth / 2; // min 50% - var chartAreaHeight = chartHeight / 2; // min 50% - - // Step 2 - var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length); - - // Step 3 - var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length); - - // Step 4 - var maxChartAreaWidth = chartWidth; - var maxChartAreaHeight = chartHeight; - var minBoxSizes = []; - - function getMinimumBoxSize(box) { - var minSize; - var isHorizontal = box.isHorizontal(); - - if (isHorizontal) { - minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight); - maxChartAreaHeight -= minSize.height; - } else { - minSize = box.update(verticalBoxWidth, maxChartAreaHeight); - maxChartAreaWidth -= minSize.width; - } - - minBoxSizes.push({ - horizontal: isHorizontal, - minSize: minSize, - box: box, - }); - } - - helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize); - - // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478) - var maxHorizontalLeftPadding = 0; - var maxHorizontalRightPadding = 0; - var maxVerticalTopPadding = 0; - var maxVerticalBottomPadding = 0; - - helpers.each(topBoxes.concat(bottomBoxes), function (horizontalBox) { - if (horizontalBox.getPadding) { - var boxPadding = horizontalBox.getPadding(); - maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left); - maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right); - } - }); - - helpers.each(leftBoxes.concat(rightBoxes), function (verticalBox) { - if (verticalBox.getPadding) { - var boxPadding = verticalBox.getPadding(); - maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top); - maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom); - } - }); - - // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could - // be if the axes are drawn at their minimum sizes. - // Steps 5 & 6 - var totalLeftBoxesWidth = leftPadding; - var totalRightBoxesWidth = rightPadding; - var totalTopBoxesHeight = topPadding; - var totalBottomBoxesHeight = bottomPadding; - - // Function to fit a box - function fitBox(box) { - var minBoxSize = helpers.findNextWhere(minBoxSizes, function (minBox) { - return minBox.box === box; - }); - - if (minBoxSize) { - if (box.isHorizontal()) { - var scaleMargin = { - left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding), - right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding), - top: 0, - bottom: 0 - }; - - // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends - // on the margin. Sometimes they need to increase in size slightly - box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin); - } else { - box.update(minBoxSize.minSize.width, maxChartAreaHeight); - } - } - } - - // Update, and calculate the left and right margins for the horizontal boxes - helpers.each(leftBoxes.concat(rightBoxes), fitBox); - - helpers.each(leftBoxes, function (box) { - totalLeftBoxesWidth += box.width; - }); - - helpers.each(rightBoxes, function (box) { - totalRightBoxesWidth += box.width; - }); - - // Set the Left and Right margins for the horizontal boxes - helpers.each(topBoxes.concat(bottomBoxes), fitBox); - - // Figure out how much margin is on the top and bottom of the vertical boxes - helpers.each(topBoxes, function (box) { - totalTopBoxesHeight += box.height; - }); - - helpers.each(bottomBoxes, function (box) { - totalBottomBoxesHeight += box.height; - }); - - function finalFitVerticalBox(box) { - var minBoxSize = helpers.findNextWhere(minBoxSizes, function (minSize) { - return minSize.box === box; - }); - - var scaleMargin = { - left: 0, - right: 0, - top: totalTopBoxesHeight, - bottom: totalBottomBoxesHeight - }; - - if (minBoxSize) { - box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin); - } - } - - // Let the left layout know the final margin - helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox); - - // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance) - totalLeftBoxesWidth = leftPadding; - totalRightBoxesWidth = rightPadding; - totalTopBoxesHeight = topPadding; - totalBottomBoxesHeight = bottomPadding; - - helpers.each(leftBoxes, function (box) { - totalLeftBoxesWidth += box.width; - }); - - helpers.each(rightBoxes, function (box) { - totalRightBoxesWidth += box.width; - }); - - helpers.each(topBoxes, function (box) { - totalTopBoxesHeight += box.height; - }); - helpers.each(bottomBoxes, function (box) { - totalBottomBoxesHeight += box.height; - }); - - // We may be adding some padding to account for rotated x axis labels - var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0); - totalLeftBoxesWidth += leftPaddingAddition; - totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0); - - var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0); - totalTopBoxesHeight += topPaddingAddition; - totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0); - - // Figure out if our chart area changed. This would occur if the dataset layout label rotation - // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do - // without calling `fit` again - var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight; - var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth; - - if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) { - helpers.each(leftBoxes, function (box) { - box.height = newMaxChartAreaHeight; - }); - - helpers.each(rightBoxes, function (box) { - box.height = newMaxChartAreaHeight; - }); - - helpers.each(topBoxes, function (box) { - if (!box.fullWidth) { - box.width = newMaxChartAreaWidth; - } - }); - - helpers.each(bottomBoxes, function (box) { - if (!box.fullWidth) { - box.width = newMaxChartAreaWidth; - } - }); - - maxChartAreaHeight = newMaxChartAreaHeight; - maxChartAreaWidth = newMaxChartAreaWidth; - } - - // Step 7 - Position the boxes - var left = leftPadding + leftPaddingAddition; - var top = topPadding + topPaddingAddition; - - function placeBox(box) { - if (box.isHorizontal()) { - box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth; - box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth; - box.top = top; - box.bottom = top + box.height; - - // Move to next point - top = box.bottom; - - } else { - - box.left = left; - box.right = left + box.width; - box.top = totalTopBoxesHeight; - box.bottom = totalTopBoxesHeight + maxChartAreaHeight; - - // Move to next point - left = box.right; - } - } - - helpers.each(leftBoxes.concat(topBoxes), placeBox); - - // Account for chart width and height - left += maxChartAreaWidth; - top += maxChartAreaHeight; - - helpers.each(rightBoxes, placeBox); - helpers.each(bottomBoxes, placeBox); - - // Step 8 - chart.chartArea = { - left: totalLeftBoxesWidth, - top: totalTopBoxesHeight, - right: totalLeftBoxesWidth + maxChartAreaWidth, - bottom: totalTopBoxesHeight + maxChartAreaHeight - }; - - // Step 9 - helpers.each(chartAreaBoxes, function (box) { - box.left = chart.chartArea.left; - box.top = chart.chartArea.top; - box.right = chart.chartArea.right; - box.bottom = chart.chartArea.bottom; - - box.update(maxChartAreaWidth, maxChartAreaHeight); - }); - } - }; - - }, { "45": 45 }], 31: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var helpers = require(45); - - defaults._set('global', { - plugins: {} - }); - - /** - * The plugin service singleton - * @namespace Chart.plugins - * @since 2.1.0 - */ - module.exports = { - /** - * Globally registered plugins. - * @private - */ - _plugins: [], - - /** - * This identifier is used to invalidate the descriptors cache attached to each chart - * when a global plugin is registered or unregistered. In this case, the cache ID is - * incremented and descriptors are regenerated during following API calls. - * @private - */ - _cacheId: 0, - - /** - * Registers the given plugin(s) if not already registered. - * @param {Array|Object} plugins plugin instance(s). - */ - register: function (plugins) { - var p = this._plugins; - ([]).concat(plugins).forEach(function (plugin) { - if (p.indexOf(plugin) === -1) { - p.push(plugin); - } - }); - - this._cacheId++; - }, - - /** - * Unregisters the given plugin(s) only if registered. - * @param {Array|Object} plugins plugin instance(s). - */ - unregister: function (plugins) { - var p = this._plugins; - ([]).concat(plugins).forEach(function (plugin) { - var idx = p.indexOf(plugin); - if (idx !== -1) { - p.splice(idx, 1); - } - }); - - this._cacheId++; - }, - - /** - * Remove all registered plugins. - * @since 2.1.5 - */ - clear: function () { - this._plugins = []; - this._cacheId++; - }, - - /** - * Returns the number of registered plugins? - * @returns {Number} - * @since 2.1.5 - */ - count: function () { - return this._plugins.length; - }, - - /** - * Returns all registered plugin instances. - * @returns {Array} array of plugin objects. - * @since 2.1.5 - */ - getAll: function () { - return this._plugins; - }, - - /** - * Calls enabled plugins for `chart` on the specified hook and with the given args. - * This method immediately returns as soon as a plugin explicitly returns false. The - * returned value can be used, for instance, to interrupt the current action. - * @param {Object} chart - The chart instance for which plugins should be called. - * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate'). - * @param {Array} [args] - Extra arguments to apply to the hook call. - * @returns {Boolean} false if any of the plugins return false, else returns true. - */ - notify: function (chart, hook, args) { - var descriptors = this.descriptors(chart); - var ilen = descriptors.length; - var i, descriptor, plugin, params, method; - - for (i = 0; i < ilen; ++i) { - descriptor = descriptors[i]; - plugin = descriptor.plugin; - method = plugin[hook]; - if (typeof method === 'function') { - params = [chart].concat(args || []); - params.push(descriptor.options); - if (method.apply(plugin, params) === false) { - return false; - } - } - } - - return true; - }, - - /** - * Returns descriptors of enabled plugins for the given chart. - * @returns {Array} [{ plugin, options }] - * @private - */ - descriptors: function (chart) { - var cache = chart.$plugins || (chart.$plugins = {}); - if (cache.id === this._cacheId) { - return cache.descriptors; - } - - var plugins = []; - var descriptors = []; - var config = (chart && chart.config) || {}; - var options = (config.options && config.options.plugins) || {}; - - this._plugins.concat(config.plugins || []).forEach(function (plugin) { - var idx = plugins.indexOf(plugin); - if (idx !== -1) { - return; - } - - var id = plugin.id; - var opts = options[id]; - if (opts === false) { - return; - } - - if (opts === true) { - opts = helpers.clone(defaults.global.plugins[id]); - } - - plugins.push(plugin); - descriptors.push({ - plugin: plugin, - options: opts || {} - }); - }); - - cache.descriptors = descriptors; - cache.id = this._cacheId; - return descriptors; - }, - - /** - * Invalidates cache for the given chart: descriptors hold a reference on plugin option, - * but in some cases, this reference can be changed by the user when updating options. - * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167 - * @private - */ - _invalidate: function (chart) { - delete chart.$plugins; - } - }; - - /** - * Plugin extension hooks. - * @interface IPlugin - * @since 2.1.0 - */ - /** - * @method IPlugin#beforeInit - * @desc Called before initializing `chart`. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#afterInit - * @desc Called after `chart` has been initialized and before the first update. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeUpdate - * @desc Called before updating `chart`. If any plugin returns `false`, the update - * is cancelled (and thus subsequent render(s)) until another `update` is triggered. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart update. - */ - /** - * @method IPlugin#afterUpdate - * @desc Called after `chart` has been updated and before rendering. Note that this - * hook will not be called if the chart update has been previously cancelled. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeDatasetsUpdate - * @desc Called before updating the `chart` datasets. If any plugin returns `false`, - * the datasets update is cancelled until another `update` is triggered. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - * @returns {Boolean} false to cancel the datasets update. - * @since version 2.1.5 - */ - /** - * @method IPlugin#afterDatasetsUpdate - * @desc Called after the `chart` datasets have been updated. Note that this hook - * will not be called if the datasets update has been previously cancelled. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - * @since version 2.1.5 - */ - /** - * @method IPlugin#beforeDatasetUpdate - * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin - * returns `false`, the datasets update is cancelled until another `update` is triggered. - * @param {Chart} chart - The chart instance. - * @param {Object} args - The call arguments. - * @param {Number} args.index - The dataset index. - * @param {Object} args.meta - The dataset metadata. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart datasets drawing. - */ - /** - * @method IPlugin#afterDatasetUpdate - * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note - * that this hook will not be called if the datasets update has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {Object} args - The call arguments. - * @param {Number} args.index - The dataset index. - * @param {Object} args.meta - The dataset metadata. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeLayout - * @desc Called before laying out `chart`. If any plugin returns `false`, - * the layout update is cancelled until another `update` is triggered. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart layout. - */ - /** - * @method IPlugin#afterLayout - * @desc Called after the `chart` has been layed out. Note that this hook will not - * be called if the layout update has been previously cancelled. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeRender - * @desc Called before rendering `chart`. If any plugin returns `false`, - * the rendering is cancelled until another `render` is triggered. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart rendering. - */ - /** - * @method IPlugin#afterRender - * @desc Called after the `chart` has been fully rendered (and animation completed). Note - * that this hook will not be called if the rendering has been previously cancelled. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeDraw - * @desc Called before drawing `chart` at every animation frame specified by the given - * easing value. If any plugin returns `false`, the frame drawing is cancelled until - * another `render` is triggered. - * @param {Chart.Controller} chart - The chart instance. - * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart drawing. - */ - /** - * @method IPlugin#afterDraw - * @desc Called after the `chart` has been drawn for the specific easing value. Note - * that this hook will not be called if the drawing has been previously cancelled. - * @param {Chart.Controller} chart - The chart instance. - * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeDatasetsDraw - * @desc Called before drawing the `chart` datasets. If any plugin returns `false`, - * the datasets drawing is cancelled until another `render` is triggered. - * @param {Chart.Controller} chart - The chart instance. - * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart datasets drawing. - */ - /** - * @method IPlugin#afterDatasetsDraw - * @desc Called after the `chart` datasets have been drawn. Note that this hook - * will not be called if the datasets drawing has been previously cancelled. - * @param {Chart.Controller} chart - The chart instance. - * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeDatasetDraw - * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets - * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing - * is cancelled until another `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {Object} args - The call arguments. - * @param {Number} args.index - The dataset index. - * @param {Object} args.meta - The dataset metadata. - * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart datasets drawing. - */ - /** - * @method IPlugin#afterDatasetDraw - * @desc Called after the `chart` datasets at the given `args.index` have been drawn - * (datasets are drawn in the reverse order). Note that this hook will not be called - * if the datasets drawing has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {Object} args - The call arguments. - * @param {Number} args.index - The dataset index. - * @param {Object} args.meta - The dataset metadata. - * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeTooltipDraw - * @desc Called before drawing the `tooltip`. If any plugin returns `false`, - * the tooltip drawing is cancelled until another `render` is triggered. - * @param {Chart} chart - The chart instance. - * @param {Object} args - The call arguments. - * @param {Object} args.tooltip - The tooltip. - * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - * @returns {Boolean} `false` to cancel the chart tooltip drawing. - */ - /** - * @method IPlugin#afterTooltipDraw - * @desc Called after drawing the `tooltip`. Note that this hook will not - * be called if the tooltip drawing has been previously cancelled. - * @param {Chart} chart - The chart instance. - * @param {Object} args - The call arguments. - * @param {Object} args.tooltip - The tooltip. - * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#beforeEvent - * @desc Called before processing the specified `event`. If any plugin returns `false`, - * the event will be discarded. - * @param {Chart.Controller} chart - The chart instance. - * @param {IEvent} event - The event object. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#afterEvent - * @desc Called after the `event` has been consumed. Note that this hook - * will not be called if the `event` has been previously discarded. - * @param {Chart.Controller} chart - The chart instance. - * @param {IEvent} event - The event object. - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#resize - * @desc Called after the chart as been resized. - * @param {Chart.Controller} chart - The chart instance. - * @param {Number} size - The new canvas display size (eq. canvas.style width & height). - * @param {Object} options - The plugin options. - */ - /** - * @method IPlugin#destroy - * @desc Called after the chart as been destroyed. - * @param {Chart.Controller} chart - The chart instance. - * @param {Object} options - The plugin options. - */ - - }, { "25": 25, "45": 45 }], 32: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - var Ticks = require(34); - - defaults._set('scale', { - display: true, - position: 'left', - offset: false, - - // grid line settings - gridLines: { - display: true, - color: 'rgba(0, 0, 0, 0.1)', - lineWidth: 1, - drawBorder: true, - drawOnChartArea: true, - drawTicks: true, - tickMarkLength: 10, - zeroLineWidth: 1, - zeroLineColor: 'rgba(0,0,0,0.25)', - zeroLineBorderDash: [], - zeroLineBorderDashOffset: 0.0, - offsetGridLines: false, - borderDash: [], - borderDashOffset: 0.0 - }, - - // scale label - scaleLabel: { - // display property - display: false, - - // actual label - labelString: '', - - // line height - lineHeight: 1.2, - - // top/bottom padding - padding: { - top: 4, - bottom: 4 - } - }, - - // label settings - ticks: { - beginAtZero: false, - minRotation: 0, - maxRotation: 50, - mirror: false, - padding: 0, - reverse: false, - display: true, - autoSkip: true, - autoSkipPadding: 0, - labelOffset: 0, - // We pass through arrays to be rendered as multiline labels, we convert Others to strings here. - callback: Ticks.formatters.values, - minor: {}, - major: {} - } - }); - - function labelsFromTicks(ticks) { - var labels = []; - var i, ilen; - - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - labels.push(ticks[i].label); - } - - return labels; - } - - function getLineValue(scale, index, offsetGridLines) { - var lineValue = scale.getPixelForTick(index); - - if (offsetGridLines) { - if (index === 0) { - lineValue -= (scale.getPixelForTick(1) - lineValue) / 2; - } else { - lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2; - } - } - return lineValue; - } - - module.exports = function (Chart) { - - function computeTextSize(context, tick, font) { - return helpers.isArray(tick) ? - helpers.longestText(context, font, tick) : - context.measureText(tick).width; - } - - function parseFontOptions(options) { - var valueOrDefault = helpers.valueOrDefault; - var globalDefaults = defaults.global; - var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize); - var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle); - var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily); - - return { - size: size, - style: style, - family: family, - font: helpers.fontString(size, style, family) - }; - } - - function parseLineHeight(options) { - return helpers.options.toLineHeight( - helpers.valueOrDefault(options.lineHeight, 1.2), - helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize)); - } - - Chart.Scale = Element.extend({ - /** - * Get the padding needed for the scale - * @method getPadding - * @private - * @returns {Padding} the necessary padding - */ - getPadding: function () { - var me = this; - return { - left: me.paddingLeft || 0, - top: me.paddingTop || 0, - right: me.paddingRight || 0, - bottom: me.paddingBottom || 0 - }; - }, - - /** - * Returns the scale tick objects ({label, major}) - * @since 2.7 - */ - getTicks: function () { - return this._ticks; - }, - - // These methods are ordered by lifecyle. Utilities then follow. - // Any function defined here is inherited by all scale types. - // Any function can be extended by the scale type - - mergeTicksOptions: function () { - var ticks = this.options.ticks; - if (ticks.minor === false) { - ticks.minor = { - display: false - }; - } - if (ticks.major === false) { - ticks.major = { - display: false - }; - } - for (var key in ticks) { - if (key !== 'major' && key !== 'minor') { - if (typeof ticks.minor[key] === 'undefined') { - ticks.minor[key] = ticks[key]; - } - if (typeof ticks.major[key] === 'undefined') { - ticks.major[key] = ticks[key]; - } - } - } - }, - beforeUpdate: function () { - helpers.callback(this.options.beforeUpdate, [this]); - }, - update: function (maxWidth, maxHeight, margins) { - var me = this; - var i, ilen, labels, label, ticks, tick; - - // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) - me.beforeUpdate(); - - // Absorb the master measurements - me.maxWidth = maxWidth; - me.maxHeight = maxHeight; - me.margins = helpers.extend({ - left: 0, - right: 0, - top: 0, - bottom: 0 - }, margins); - me.longestTextCache = me.longestTextCache || {}; - - // Dimensions - me.beforeSetDimensions(); - me.setDimensions(); - me.afterSetDimensions(); - - // Data min/max - me.beforeDataLimits(); - me.determineDataLimits(); - me.afterDataLimits(); - - // Ticks - `this.ticks` is now DEPRECATED! - // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member - // and must not be accessed directly from outside this class. `this.ticks` being - // around for long time and not marked as private, we can't change its structure - // without unexpected breaking changes. If you need to access the scale ticks, - // use scale.getTicks() instead. - - me.beforeBuildTicks(); - - // New implementations should return an array of objects but for BACKWARD COMPAT, - // we still support no return (`this.ticks` internally set by calling this method). - ticks = me.buildTicks() || []; - - me.afterBuildTicks(); - - me.beforeTickToLabelConversion(); - - // New implementations should return the formatted tick labels but for BACKWARD - // COMPAT, we still support no return (`this.ticks` internally changed by calling - // this method and supposed to contain only string values). - labels = me.convertTicksToLabels(ticks) || me.ticks; - - me.afterTickToLabelConversion(); - - me.ticks = labels; // BACKWARD COMPATIBILITY - - // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change! - - // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`) - for (i = 0, ilen = labels.length; i < ilen; ++i) { - label = labels[i]; - tick = ticks[i]; - if (!tick) { - ticks.push(tick = { - label: label, - major: false - }); - } else { - tick.label = label; - } - } - - me._ticks = ticks; - - // Tick Rotation - me.beforeCalculateTickRotation(); - me.calculateTickRotation(); - me.afterCalculateTickRotation(); - // Fit - me.beforeFit(); - me.fit(); - me.afterFit(); - // - me.afterUpdate(); - - return me.minSize; - - }, - afterUpdate: function () { - helpers.callback(this.options.afterUpdate, [this]); - }, - - // - - beforeSetDimensions: function () { - helpers.callback(this.options.beforeSetDimensions, [this]); - }, - setDimensions: function () { - var me = this; - // Set the unconstrained dimension before label rotation - if (me.isHorizontal()) { - // Reset position before calculating rotation - me.width = me.maxWidth; - me.left = 0; - me.right = me.width; - } else { - me.height = me.maxHeight; - - // Reset position before calculating rotation - me.top = 0; - me.bottom = me.height; - } - - // Reset padding - me.paddingLeft = 0; - me.paddingTop = 0; - me.paddingRight = 0; - me.paddingBottom = 0; - }, - afterSetDimensions: function () { - helpers.callback(this.options.afterSetDimensions, [this]); - }, - - // Data limits - beforeDataLimits: function () { - helpers.callback(this.options.beforeDataLimits, [this]); - }, - determineDataLimits: helpers.noop, - afterDataLimits: function () { - helpers.callback(this.options.afterDataLimits, [this]); - }, - - // - beforeBuildTicks: function () { - helpers.callback(this.options.beforeBuildTicks, [this]); - }, - buildTicks: helpers.noop, - afterBuildTicks: function () { - helpers.callback(this.options.afterBuildTicks, [this]); - }, - - beforeTickToLabelConversion: function () { - helpers.callback(this.options.beforeTickToLabelConversion, [this]); - }, - convertTicksToLabels: function () { - var me = this; - // Convert ticks to strings - var tickOpts = me.options.ticks; - me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this); - }, - afterTickToLabelConversion: function () { - helpers.callback(this.options.afterTickToLabelConversion, [this]); - }, - - // - - beforeCalculateTickRotation: function () { - helpers.callback(this.options.beforeCalculateTickRotation, [this]); - }, - calculateTickRotation: function () { - var me = this; - var context = me.ctx; - var tickOpts = me.options.ticks; - var labels = labelsFromTicks(me._ticks); - - // Get the width of each grid by calculating the difference - // between x offsets between 0 and 1. - var tickFont = parseFontOptions(tickOpts); - context.font = tickFont.font; - - var labelRotation = tickOpts.minRotation || 0; - - if (labels.length && me.options.display && me.isHorizontal()) { - var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache); - var labelWidth = originalLabelWidth; - var cosRotation, sinRotation; - - // Allow 3 pixels x2 padding either side for label readability - var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6; - - // Max label rotation can be set or default to 90 - also act as a loop counter - while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) { - var angleRadians = helpers.toRadians(labelRotation); - cosRotation = Math.cos(angleRadians); - sinRotation = Math.sin(angleRadians); - - if (sinRotation * originalLabelWidth > me.maxHeight) { - // go back one step - labelRotation--; - break; - } - - labelRotation++; - labelWidth = cosRotation * originalLabelWidth; - } - } - - me.labelRotation = labelRotation; - }, - afterCalculateTickRotation: function () { - helpers.callback(this.options.afterCalculateTickRotation, [this]); - }, - - // - - beforeFit: function () { - helpers.callback(this.options.beforeFit, [this]); - }, - fit: function () { - var me = this; - // Reset - var minSize = me.minSize = { - width: 0, - height: 0 - }; - - var labels = labelsFromTicks(me._ticks); - - var opts = me.options; - var tickOpts = opts.ticks; - var scaleLabelOpts = opts.scaleLabel; - var gridLineOpts = opts.gridLines; - var display = opts.display; - var isHorizontal = me.isHorizontal(); - - var tickFont = parseFontOptions(tickOpts); - var tickMarkLength = opts.gridLines.tickMarkLength; - - // Width - if (isHorizontal) { - // subtract the margins to line up with the chartArea if we are a full width scale - minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth; - } else { - minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0; - } - - // height - if (isHorizontal) { - minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0; - } else { - minSize.height = me.maxHeight; // fill all the height - } - - // Are we showing a title for the scale? - if (scaleLabelOpts.display && display) { - var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts); - var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding); - var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height; - - if (isHorizontal) { - minSize.height += deltaHeight; - } else { - minSize.width += deltaHeight; - } - } - - // Don't bother fitting the ticks if we are not showing them - if (tickOpts.display && display) { - var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache); - var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels); - var lineSpace = tickFont.size * 0.5; - var tickPadding = me.options.ticks.padding; - - if (isHorizontal) { - // A horizontal axis is more constrained by the height. - me.longestLabelWidth = largestTextWidth; - - var angleRadians = helpers.toRadians(me.labelRotation); - var cosRotation = Math.cos(angleRadians); - var sinRotation = Math.sin(angleRadians); - - // TODO - improve this calculation - var labelHeight = (sinRotation * largestTextWidth) - + (tickFont.size * tallestLabelHeightInLines) - + (lineSpace * (tallestLabelHeightInLines - 1)) - + lineSpace; // padding - - minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding); - - me.ctx.font = tickFont.font; - var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font); - var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font); - - // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned - // which means that the right padding is dominated by the font height - if (me.labelRotation !== 0) { - me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges - me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3; - } else { - me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges - me.paddingRight = lastLabelWidth / 2 + 3; - } - } else { - // A vertical axis is more constrained by the width. Labels are the - // dominant factor here, so get that length first and account for padding - if (tickOpts.mirror) { - largestTextWidth = 0; - } else { - // use lineSpace for consistency with horizontal axis - // tickPadding is not implemented for horizontal - largestTextWidth += tickPadding + lineSpace; - } - - minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth); - - me.paddingTop = tickFont.size / 2; - me.paddingBottom = tickFont.size / 2; - } - } - - me.handleMargins(); - - me.width = minSize.width; - me.height = minSize.height; - }, - - /** - * Handle margins and padding interactions - * @private - */ - handleMargins: function () { - var me = this; - if (me.margins) { - me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0); - me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0); - me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0); - me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0); - } - }, - - afterFit: function () { - helpers.callback(this.options.afterFit, [this]); - }, - - // Shared Methods - isHorizontal: function () { - return this.options.position === 'top' || this.options.position === 'bottom'; - }, - isFullWidth: function () { - return (this.options.fullWidth); - }, - - // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not - getRightValue: function (rawValue) { - // Null and undefined values first - if (helpers.isNullOrUndef(rawValue)) { - return NaN; - } - // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values - if (typeof rawValue === 'number' && !isFinite(rawValue)) { - return NaN; - } - // If it is in fact an object, dive in one more level - if (rawValue) { - if (this.isHorizontal()) { - if (rawValue.x !== undefined) { - return this.getRightValue(rawValue.x); - } - } else if (rawValue.y !== undefined) { - return this.getRightValue(rawValue.y); - } - } - - // Value is good, return it - return rawValue; - }, - - /** - * Used to get the value to display in the tooltip for the data at the given index - * @param index - * @param datasetIndex - */ - getLabelForIndex: helpers.noop, - - /** - * Returns the location of the given data point. Value can either be an index or a numerical value - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @param value - * @param index - * @param datasetIndex - */ - getPixelForValue: helpers.noop, - - /** - * Used to get the data value from a given pixel. This is the inverse of getPixelForValue - * The coordinate (0, 0) is at the upper-left corner of the canvas - * @param pixel - */ - getValueForPixel: helpers.noop, - - /** - * Returns the location of the tick at the given index - * The coordinate (0, 0) is at the upper-left corner of the canvas - */ - getPixelForTick: function (index) { - var me = this; - var offset = me.options.offset; - if (me.isHorizontal()) { - var innerWidth = me.width - (me.paddingLeft + me.paddingRight); - var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1); - var pixel = (tickWidth * index) + me.paddingLeft; - - if (offset) { - pixel += tickWidth / 2; - } - - var finalVal = me.left + Math.round(pixel); - finalVal += me.isFullWidth() ? me.margins.left : 0; - return finalVal; - } - var innerHeight = me.height - (me.paddingTop + me.paddingBottom); - return me.top + (index * (innerHeight / (me._ticks.length - 1))); - }, - - /** - * Utility for getting the pixel location of a percentage of scale - * The coordinate (0, 0) is at the upper-left corner of the canvas - */ - getPixelForDecimal: function (decimal) { - var me = this; - if (me.isHorizontal()) { - var innerWidth = me.width - (me.paddingLeft + me.paddingRight); - var valueOffset = (innerWidth * decimal) + me.paddingLeft; - - var finalVal = me.left + Math.round(valueOffset); - finalVal += me.isFullWidth() ? me.margins.left : 0; - return finalVal; - } - return me.top + (decimal * me.height); - }, - - /** - * Returns the pixel for the minimum chart value - * The coordinate (0, 0) is at the upper-left corner of the canvas - */ - getBasePixel: function () { - return this.getPixelForValue(this.getBaseValue()); - }, - - getBaseValue: function () { - var me = this; - var min = me.min; - var max = me.max; - - return me.beginAtZero ? 0 : - min < 0 && max < 0 ? max : - min > 0 && max > 0 ? min : - 0; - }, - - /** - * Returns a subset of ticks to be plotted to avoid overlapping labels. - * @private - */ - _autoSkip: function (ticks) { - var skipRatio; - var me = this; - var isHorizontal = me.isHorizontal(); - var optionTicks = me.options.ticks.minor; - var tickCount = ticks.length; - var labelRotationRadians = helpers.toRadians(me.labelRotation); - var cosRotation = Math.cos(labelRotationRadians); - var longestRotatedLabel = me.longestLabelWidth * cosRotation; - var result = []; - var i, tick, shouldSkip; - - // figure out the maximum number of gridlines to show - var maxTicks; - if (optionTicks.maxTicksLimit) { - maxTicks = optionTicks.maxTicksLimit; - } - - if (isHorizontal) { - skipRatio = false; - - if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) { - skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight))); - } - - // if they defined a max number of optionTicks, - // increase skipRatio until that number is met - if (maxTicks && tickCount > maxTicks) { - skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks)); - } - } - - for (i = 0; i < tickCount; i++) { - tick = ticks[i]; - - // Since we always show the last tick,we need may need to hide the last shown one before - shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount); - if (shouldSkip && i !== tickCount - 1) { - // leave tick in place but make sure it's not displayed (#4635) - delete tick.label; - } - result.push(tick); - } - return result; - }, - - // Actually draw the scale on the canvas - // @param {rectangle} chartArea : the area of the chart to draw full grid lines on - draw: function (chartArea) { - var me = this; - var options = me.options; - if (!options.display) { - return; - } - - var context = me.ctx; - var globalDefaults = defaults.global; - var optionTicks = options.ticks.minor; - var optionMajorTicks = options.ticks.major || optionTicks; - var gridLines = options.gridLines; - var scaleLabel = options.scaleLabel; - - var isRotated = me.labelRotation !== 0; - var isHorizontal = me.isHorizontal(); - - var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks(); - var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor); - var tickFont = parseFontOptions(optionTicks); - var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor); - var majorTickFont = parseFontOptions(optionMajorTicks); - - var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0; - - var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor); - var scaleLabelFont = parseFontOptions(scaleLabel); - var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding); - var labelRotationRadians = helpers.toRadians(me.labelRotation); - - var itemsToDraw = []; - - var axisWidth = me.options.gridLines.lineWidth; - var xTickStart = options.position === 'right' ? me.right : me.right - axisWidth - tl; - var xTickEnd = options.position === 'right' ? me.right + tl : me.right; - var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth; - var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth; - - helpers.each(ticks, function (tick, index) { - // autoskipper skipped this tick (#4635) - if (helpers.isNullOrUndef(tick.label)) { - return; - } - - var label = tick.label; - var lineWidth, lineColor, borderDash, borderDashOffset; - if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) { - // Draw the first index specially - lineWidth = gridLines.zeroLineWidth; - lineColor = gridLines.zeroLineColor; - borderDash = gridLines.zeroLineBorderDash; - borderDashOffset = gridLines.zeroLineBorderDashOffset; - } else { - lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index); - lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index); - borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash); - borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset); - } - - // Common properties - var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY; - var textAlign = 'middle'; - var textBaseline = 'middle'; - var tickPadding = optionTicks.padding; - - if (isHorizontal) { - var labelYOffset = tl + tickPadding; - - if (options.position === 'bottom') { - // bottom - textBaseline = !isRotated ? 'top' : 'middle'; - textAlign = !isRotated ? 'center' : 'right'; - labelY = me.top + labelYOffset; - } else { - // top - textBaseline = !isRotated ? 'bottom' : 'middle'; - textAlign = !isRotated ? 'center' : 'left'; - labelY = me.bottom - labelYOffset; - } - - var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1); - if (xLineValue < me.left) { - lineColor = 'rgba(0,0,0,0)'; - } - xLineValue += helpers.aliasPixel(lineWidth); - - labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option) - - tx1 = tx2 = x1 = x2 = xLineValue; - ty1 = yTickStart; - ty2 = yTickEnd; - y1 = chartArea.top; - y2 = chartArea.bottom + axisWidth; - } else { - var isLeft = options.position === 'left'; - var labelXOffset; - - if (optionTicks.mirror) { - textAlign = isLeft ? 'left' : 'right'; - labelXOffset = tickPadding; - } else { - textAlign = isLeft ? 'right' : 'left'; - labelXOffset = tl + tickPadding; - } - - labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset; - - var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1); - if (yLineValue < me.top) { - lineColor = 'rgba(0,0,0,0)'; - } - yLineValue += helpers.aliasPixel(lineWidth); - - labelY = me.getPixelForTick(index) + optionTicks.labelOffset; - - tx1 = xTickStart; - tx2 = xTickEnd; - x1 = chartArea.left; - x2 = chartArea.right + axisWidth; - ty1 = ty2 = y1 = y2 = yLineValue; - } - - itemsToDraw.push({ - tx1: tx1, - ty1: ty1, - tx2: tx2, - ty2: ty2, - x1: x1, - y1: y1, - x2: x2, - y2: y2, - labelX: labelX, - labelY: labelY, - glWidth: lineWidth, - glColor: lineColor, - glBorderDash: borderDash, - glBorderDashOffset: borderDashOffset, - rotation: -1 * labelRotationRadians, - label: label, - major: tick.major, - textBaseline: textBaseline, - textAlign: textAlign - }); - }); - - // Draw all of the tick labels, tick marks, and grid lines at the correct places - helpers.each(itemsToDraw, function (itemToDraw) { - if (gridLines.display) { - context.save(); - context.lineWidth = itemToDraw.glWidth; - context.strokeStyle = itemToDraw.glColor; - if (context.setLineDash) { - context.setLineDash(itemToDraw.glBorderDash); - context.lineDashOffset = itemToDraw.glBorderDashOffset; - } - - context.beginPath(); - - if (gridLines.drawTicks) { - context.moveTo(itemToDraw.tx1, itemToDraw.ty1); - context.lineTo(itemToDraw.tx2, itemToDraw.ty2); - } - - if (gridLines.drawOnChartArea) { - context.moveTo(itemToDraw.x1, itemToDraw.y1); - context.lineTo(itemToDraw.x2, itemToDraw.y2); - } - - context.stroke(); - context.restore(); - } - - if (optionTicks.display) { - // Make sure we draw text in the correct color and font - context.save(); - context.translate(itemToDraw.labelX, itemToDraw.labelY); - context.rotate(itemToDraw.rotation); - context.font = itemToDraw.major ? majorTickFont.font : tickFont.font; - context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor; - context.textBaseline = itemToDraw.textBaseline; - context.textAlign = itemToDraw.textAlign; - - var label = itemToDraw.label; - if (helpers.isArray(label)) { - var lineCount = label.length; - var lineHeight = tickFont.size * 1.5; - var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2; - - for (var i = 0; i < lineCount; ++i) { - // We just make sure the multiline element is a string here.. - context.fillText('' + label[i], 0, y); - // apply same lineSpacing as calculated @ L#320 - y += lineHeight; - } - } else { - context.fillText(label, 0, 0); - } - context.restore(); - } - }); - - if (scaleLabel.display) { - // Draw the scale label - var scaleLabelX; - var scaleLabelY; - var rotation = 0; - var halfLineHeight = parseLineHeight(scaleLabel) / 2; - - if (isHorizontal) { - scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width - scaleLabelY = options.position === 'bottom' - ? me.bottom - halfLineHeight - scaleLabelPadding.bottom - : me.top + halfLineHeight + scaleLabelPadding.top; - } else { - var isLeft = options.position === 'left'; - scaleLabelX = isLeft - ? me.left + halfLineHeight + scaleLabelPadding.top - : me.right - halfLineHeight - scaleLabelPadding.top; - scaleLabelY = me.top + ((me.bottom - me.top) / 2); - rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI; - } - - context.save(); - context.translate(scaleLabelX, scaleLabelY); - context.rotate(rotation); - context.textAlign = 'center'; - context.textBaseline = 'middle'; - context.fillStyle = scaleLabelFontColor; // render in correct colour - context.font = scaleLabelFont.font; - context.fillText(scaleLabel.labelString, 0, 0); - context.restore(); - } - - if (gridLines.drawBorder) { - // Draw the line at the edge of the axis - context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0); - context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0); - var x1 = me.left; - var x2 = me.right + axisWidth; - var y1 = me.top; - var y2 = me.bottom + axisWidth; - - var aliasPixel = helpers.aliasPixel(context.lineWidth); - if (isHorizontal) { - y1 = y2 = options.position === 'top' ? me.bottom : me.top; - y1 += aliasPixel; - y2 += aliasPixel; - } else { - x1 = x2 = options.position === 'left' ? me.right : me.left; - x1 += aliasPixel; - x2 += aliasPixel; - } - - context.beginPath(); - context.moveTo(x1, y1); - context.lineTo(x2, y2); - context.stroke(); - } - } - }); - }; - - }, { "25": 25, "26": 26, "34": 34, "45": 45 }], 33: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var helpers = require(45); - var layouts = require(30); - - module.exports = function (Chart) { - - Chart.scaleService = { - // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then - // use the new chart options to grab the correct scale - constructors: {}, - // Use a registration function so that we can move to an ES6 map when we no longer need to support - // old browsers - - // Scale config defaults - defaults: {}, - registerScaleType: function (type, scaleConstructor, scaleDefaults) { - this.constructors[type] = scaleConstructor; - this.defaults[type] = helpers.clone(scaleDefaults); - }, - getScaleConstructor: function (type) { - return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined; - }, - getScaleDefaults: function (type) { - // Return the scale defaults merged with the global settings so that we always use the latest ones - return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {}; - }, - updateScaleDefaults: function (type, additions) { - var me = this; - if (me.defaults.hasOwnProperty(type)) { - me.defaults[type] = helpers.extend(me.defaults[type], additions); - } - }, - addScalesToLayout: function (chart) { - // Adds each scale to the chart.boxes array to be sized accordingly - helpers.each(chart.scales, function (scale) { - // Set ILayoutItem parameters for backwards compatibility - scale.fullWidth = scale.options.fullWidth; - scale.position = scale.options.position; - scale.weight = scale.options.weight; - layouts.addBox(chart, scale); - }); - } - }; - }; - - }, { "25": 25, "30": 30, "45": 45 }], 34: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - - /** - * Namespace to hold static tick generation functions - * @namespace Chart.Ticks - */ - module.exports = { - /** - * Namespace to hold formatters for different types of ticks - * @namespace Chart.Ticks.formatters - */ - formatters: { - /** - * Formatter for value labels - * @method Chart.Ticks.formatters.values - * @param value the value to display - * @return {String|Array} the label to display - */ - values: function (value) { - return helpers.isArray(value) ? value : '' + value; - }, - - /** - * Formatter for linear numeric ticks - * @method Chart.Ticks.formatters.linear - * @param tickValue {Number} the value to be formatted - * @param index {Number} the position of the tickValue parameter in the ticks array - * @param ticks {Array} the list of ticks being converted - * @return {String} string representation of the tickValue parameter - */ - linear: function (tickValue, index, ticks) { - // If we have lots of ticks, don't use the ones - var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0]; - - // If we have a number like 2.5 as the delta, figure out how many decimal places we need - if (Math.abs(delta) > 1) { - if (tickValue !== Math.floor(tickValue)) { - // not an integer - delta = tickValue - Math.floor(tickValue); - } - } - - var logDelta = helpers.log10(Math.abs(delta)); - var tickString = ''; - - if (tickValue !== 0) { - var numDecimal = -1 * Math.floor(logDelta); - numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places - tickString = tickValue.toFixed(numDecimal); - } else { - tickString = '0'; // never show decimal places for 0 - } - - return tickString; - }, - - logarithmic: function (tickValue, index, ticks) { - var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue)))); - - if (tickValue === 0) { - return '0'; - } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) { - return tickValue.toExponential(); - } - return ''; - } - } - }; - - }, { "45": 45 }], 35: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - - defaults._set('global', { - tooltips: { - enabled: true, - custom: null, - mode: 'nearest', - position: 'average', - intersect: true, - backgroundColor: 'rgba(0,0,0,0.8)', - titleFontStyle: 'bold', - titleSpacing: 2, - titleMarginBottom: 6, - titleFontColor: '#fff', - titleAlign: 'left', - bodySpacing: 2, - bodyFontColor: '#fff', - bodyAlign: 'left', - footerFontStyle: 'bold', - footerSpacing: 2, - footerMarginTop: 6, - footerFontColor: '#fff', - footerAlign: 'left', - yPadding: 6, - xPadding: 6, - caretPadding: 2, - caretSize: 5, - cornerRadius: 6, - multiKeyBackground: '#fff', - displayColors: true, - borderColor: 'rgba(0,0,0,0)', - borderWidth: 0, - callbacks: { - // Args are: (tooltipItems, data) - beforeTitle: helpers.noop, - title: function (tooltipItems, data) { - // Pick first xLabel for now - var title = ''; - var labels = data.labels; - var labelCount = labels ? labels.length : 0; - - if (tooltipItems.length > 0) { - var item = tooltipItems[0]; - - if (item.xLabel) { - title = item.xLabel; - } else if (labelCount > 0 && item.index < labelCount) { - title = labels[item.index]; - } - } - - return title; - }, - afterTitle: helpers.noop, - - // Args are: (tooltipItems, data) - beforeBody: helpers.noop, - - // Args are: (tooltipItem, data) - beforeLabel: helpers.noop, - label: function (tooltipItem, data) { - var label = data.datasets[tooltipItem.datasetIndex].label || ''; - - if (label) { - label += ': '; - } - label += tooltipItem.yLabel; - return label; - }, - labelColor: function (tooltipItem, chart) { - var meta = chart.getDatasetMeta(tooltipItem.datasetIndex); - var activeElement = meta.data[tooltipItem.index]; - var view = activeElement._view; - return { - borderColor: view.borderColor, - backgroundColor: view.backgroundColor - }; - }, - labelTextColor: function () { - return this._options.bodyFontColor; - }, - afterLabel: helpers.noop, - - // Args are: (tooltipItems, data) - afterBody: helpers.noop, - - // Args are: (tooltipItems, data) - beforeFooter: helpers.noop, - footer: helpers.noop, - afterFooter: helpers.noop - } - } - }); - - module.exports = function (Chart) { - - /** - * Helper method to merge the opacity into a color - */ - function mergeOpacity(colorString, opacity) { - var color = helpers.color(colorString); - return color.alpha(opacity * color.alpha()).rgbaString(); - } - - // Helper to push or concat based on if the 2nd parameter is an array or not - function pushOrConcat(base, toPush) { - if (toPush) { - if (helpers.isArray(toPush)) { - // base = base.concat(toPush); - Array.prototype.push.apply(base, toPush); - } else { - base.push(toPush); - } - } - - return base; - } - - // Private helper to create a tooltip item model - // @param element : the chart element (point, arc, bar) to create the tooltip item for - // @return : new tooltip item - function createTooltipItem(element) { - var xScale = element._xScale; - var yScale = element._yScale || element._scale; // handle radar || polarArea charts - var index = element._index; - var datasetIndex = element._datasetIndex; - - return { - xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '', - yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '', - index: index, - datasetIndex: datasetIndex, - x: element._model.x, - y: element._model.y - }; - } - - /** - * Helper to get the reset model for the tooltip - * @param tooltipOpts {Object} the tooltip options - */ - function getBaseModel(tooltipOpts) { - var globalDefaults = defaults.global; - var valueOrDefault = helpers.valueOrDefault; - - return { - // Positioning - xPadding: tooltipOpts.xPadding, - yPadding: tooltipOpts.yPadding, - xAlign: tooltipOpts.xAlign, - yAlign: tooltipOpts.yAlign, - - // Body - bodyFontColor: tooltipOpts.bodyFontColor, - _bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily), - _bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle), - _bodyAlign: tooltipOpts.bodyAlign, - bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize), - bodySpacing: tooltipOpts.bodySpacing, - - // Title - titleFontColor: tooltipOpts.titleFontColor, - _titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily), - _titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle), - titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize), - _titleAlign: tooltipOpts.titleAlign, - titleSpacing: tooltipOpts.titleSpacing, - titleMarginBottom: tooltipOpts.titleMarginBottom, - - // Footer - footerFontColor: tooltipOpts.footerFontColor, - _footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily), - _footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle), - footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize), - _footerAlign: tooltipOpts.footerAlign, - footerSpacing: tooltipOpts.footerSpacing, - footerMarginTop: tooltipOpts.footerMarginTop, - - // Appearance - caretSize: tooltipOpts.caretSize, - cornerRadius: tooltipOpts.cornerRadius, - backgroundColor: tooltipOpts.backgroundColor, - opacity: 0, - legendColorBackground: tooltipOpts.multiKeyBackground, - displayColors: tooltipOpts.displayColors, - borderColor: tooltipOpts.borderColor, - borderWidth: tooltipOpts.borderWidth - }; - } - - /** - * Get the size of the tooltip - */ - function getTooltipSize(tooltip, model) { - var ctx = tooltip._chart.ctx; - - var height = model.yPadding * 2; // Tooltip Padding - var width = 0; - - // Count of all lines in the body - var body = model.body; - var combinedBodyLength = body.reduce(function (count, bodyItem) { - return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length; - }, 0); - combinedBodyLength += model.beforeBody.length + model.afterBody.length; - - var titleLineCount = model.title.length; - var footerLineCount = model.footer.length; - var titleFontSize = model.titleFontSize; - var bodyFontSize = model.bodyFontSize; - var footerFontSize = model.footerFontSize; - - height += titleLineCount * titleFontSize; // Title Lines - height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing - height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin - height += combinedBodyLength * bodyFontSize; // Body Lines - height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing - height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin - height += footerLineCount * (footerFontSize); // Footer Lines - height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing - - // Title width - var widthPadding = 0; - var maxLineWidth = function (line) { - width = Math.max(width, ctx.measureText(line).width + widthPadding); - }; - - ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily); - helpers.each(model.title, maxLineWidth); - - // Body width - ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily); - helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth); - - // Body lines may include some extra width due to the color box - widthPadding = model.displayColors ? (bodyFontSize + 2) : 0; - helpers.each(body, function (bodyItem) { - helpers.each(bodyItem.before, maxLineWidth); - helpers.each(bodyItem.lines, maxLineWidth); - helpers.each(bodyItem.after, maxLineWidth); - }); - - // Reset back to 0 - widthPadding = 0; - - // Footer width - ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily); - helpers.each(model.footer, maxLineWidth); - - // Add padding - width += 2 * model.xPadding; - - return { - width: width, - height: height - }; - } - - /** - * Helper to get the alignment of a tooltip given the size - */ - function determineAlignment(tooltip, size) { - var model = tooltip._model; - var chart = tooltip._chart; - var chartArea = tooltip._chart.chartArea; - var xAlign = 'center'; - var yAlign = 'center'; - - if (model.y < size.height) { - yAlign = 'top'; - } else if (model.y > (chart.height - size.height)) { - yAlign = 'bottom'; - } - - var lf, rf; // functions to determine left, right alignment - var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart - var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges - var midX = (chartArea.left + chartArea.right) / 2; - var midY = (chartArea.top + chartArea.bottom) / 2; - - if (yAlign === 'center') { - lf = function (x) { - return x <= midX; - }; - rf = function (x) { - return x > midX; - }; - } else { - lf = function (x) { - return x <= (size.width / 2); - }; - rf = function (x) { - return x >= (chart.width - (size.width / 2)); - }; - } - - olf = function (x) { - return x + size.width + model.caretSize + model.caretPadding > chart.width; - }; - orf = function (x) { - return x - size.width - model.caretSize - model.caretPadding < 0; - }; - yf = function (y) { - return y <= midY ? 'top' : 'bottom'; - }; - - if (lf(model.x)) { - xAlign = 'left'; - - // Is tooltip too wide and goes over the right side of the chart.? - if (olf(model.x)) { - xAlign = 'center'; - yAlign = yf(model.y); - } - } else if (rf(model.x)) { - xAlign = 'right'; - - // Is tooltip too wide and goes outside left edge of canvas? - if (orf(model.x)) { - xAlign = 'center'; - yAlign = yf(model.y); - } - } - - var opts = tooltip._options; - return { - xAlign: opts.xAlign ? opts.xAlign : xAlign, - yAlign: opts.yAlign ? opts.yAlign : yAlign - }; - } - - /** - * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment - */ - function getBackgroundPoint(vm, size, alignment, chart) { - // Background Position - var x = vm.x; - var y = vm.y; - - var caretSize = vm.caretSize; - var caretPadding = vm.caretPadding; - var cornerRadius = vm.cornerRadius; - var xAlign = alignment.xAlign; - var yAlign = alignment.yAlign; - var paddingAndSize = caretSize + caretPadding; - var radiusAndPadding = cornerRadius + caretPadding; - - if (xAlign === 'right') { - x -= size.width; - } else if (xAlign === 'center') { - x -= (size.width / 2); - if (x + size.width > chart.width) { - x = chart.width - size.width; - } - if (x < 0) { - x = 0; - } - } - - if (yAlign === 'top') { - y += paddingAndSize; - } else if (yAlign === 'bottom') { - y -= size.height + paddingAndSize; - } else { - y -= (size.height / 2); - } - - if (yAlign === 'center') { - if (xAlign === 'left') { - x += paddingAndSize; - } else if (xAlign === 'right') { - x -= paddingAndSize; - } - } else if (xAlign === 'left') { - x -= radiusAndPadding; - } else if (xAlign === 'right') { - x += radiusAndPadding; - } - - return { - x: x, - y: y - }; - } - - Chart.Tooltip = Element.extend({ - initialize: function () { - this._model = getBaseModel(this._options); - this._lastActive = []; - }, - - // Get the title - // Args are: (tooltipItem, data) - getTitle: function () { - var me = this; - var opts = me._options; - var callbacks = opts.callbacks; - - var beforeTitle = callbacks.beforeTitle.apply(me, arguments); - var title = callbacks.title.apply(me, arguments); - var afterTitle = callbacks.afterTitle.apply(me, arguments); - - var lines = []; - lines = pushOrConcat(lines, beforeTitle); - lines = pushOrConcat(lines, title); - lines = pushOrConcat(lines, afterTitle); - - return lines; - }, - - // Args are: (tooltipItem, data) - getBeforeBody: function () { - var lines = this._options.callbacks.beforeBody.apply(this, arguments); - return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; - }, - - // Args are: (tooltipItem, data) - getBody: function (tooltipItems, data) { - var me = this; - var callbacks = me._options.callbacks; - var bodyItems = []; - - helpers.each(tooltipItems, function (tooltipItem) { - var bodyItem = { - before: [], - lines: [], - after: [] - }; - pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data)); - pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data)); - pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data)); - - bodyItems.push(bodyItem); - }); - - return bodyItems; - }, - - // Args are: (tooltipItem, data) - getAfterBody: function () { - var lines = this._options.callbacks.afterBody.apply(this, arguments); - return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; - }, - - // Get the footer and beforeFooter and afterFooter lines - // Args are: (tooltipItem, data) - getFooter: function () { - var me = this; - var callbacks = me._options.callbacks; - - var beforeFooter = callbacks.beforeFooter.apply(me, arguments); - var footer = callbacks.footer.apply(me, arguments); - var afterFooter = callbacks.afterFooter.apply(me, arguments); - - var lines = []; - lines = pushOrConcat(lines, beforeFooter); - lines = pushOrConcat(lines, footer); - lines = pushOrConcat(lines, afterFooter); - - return lines; - }, - - update: function (changed) { - var me = this; - var opts = me._options; - - // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition - // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time - // which breaks any animations. - var existingModel = me._model; - var model = me._model = getBaseModel(opts); - var active = me._active; - - var data = me._data; - - // In the case where active.length === 0 we need to keep these at existing values for good animations - var alignment = { - xAlign: existingModel.xAlign, - yAlign: existingModel.yAlign - }; - var backgroundPoint = { - x: existingModel.x, - y: existingModel.y - }; - var tooltipSize = { - width: existingModel.width, - height: existingModel.height - }; - var tooltipPosition = { - x: existingModel.caretX, - y: existingModel.caretY - }; - - var i, len; - - if (active.length) { - model.opacity = 1; - - var labelColors = []; - var labelTextColors = []; - tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition); - - var tooltipItems = []; - for (i = 0, len = active.length; i < len; ++i) { - tooltipItems.push(createTooltipItem(active[i])); - } - - // If the user provided a filter function, use it to modify the tooltip items - if (opts.filter) { - tooltipItems = tooltipItems.filter(function (a) { - return opts.filter(a, data); - }); - } - - // If the user provided a sorting function, use it to modify the tooltip items - if (opts.itemSort) { - tooltipItems = tooltipItems.sort(function (a, b) { - return opts.itemSort(a, b, data); - }); - } - - // Determine colors for boxes - helpers.each(tooltipItems, function (tooltipItem) { - labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart)); - labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart)); - }); - - - // Build the Text Lines - model.title = me.getTitle(tooltipItems, data); - model.beforeBody = me.getBeforeBody(tooltipItems, data); - model.body = me.getBody(tooltipItems, data); - model.afterBody = me.getAfterBody(tooltipItems, data); - model.footer = me.getFooter(tooltipItems, data); - - // Initial positioning and colors - model.x = Math.round(tooltipPosition.x); - model.y = Math.round(tooltipPosition.y); - model.caretPadding = opts.caretPadding; - model.labelColors = labelColors; - model.labelTextColors = labelTextColors; - - // data points - model.dataPoints = tooltipItems; - - // We need to determine alignment of the tooltip - tooltipSize = getTooltipSize(this, model); - alignment = determineAlignment(this, tooltipSize); - // Final Size and Position - backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart); - } else { - model.opacity = 0; - } - - model.xAlign = alignment.xAlign; - model.yAlign = alignment.yAlign; - model.x = backgroundPoint.x; - model.y = backgroundPoint.y; - model.width = tooltipSize.width; - model.height = tooltipSize.height; - - // Point where the caret on the tooltip points to - model.caretX = tooltipPosition.x; - model.caretY = tooltipPosition.y; - - me._model = model; - - if (changed && opts.custom) { - opts.custom.call(me, model); - } - - return me; - }, - drawCaret: function (tooltipPoint, size) { - var ctx = this._chart.ctx; - var vm = this._view; - var caretPosition = this.getCaretPosition(tooltipPoint, size, vm); - - ctx.lineTo(caretPosition.x1, caretPosition.y1); - ctx.lineTo(caretPosition.x2, caretPosition.y2); - ctx.lineTo(caretPosition.x3, caretPosition.y3); - }, - getCaretPosition: function (tooltipPoint, size, vm) { - var x1, x2, x3, y1, y2, y3; - var caretSize = vm.caretSize; - var cornerRadius = vm.cornerRadius; - var xAlign = vm.xAlign; - var yAlign = vm.yAlign; - var ptX = tooltipPoint.x; - var ptY = tooltipPoint.y; - var width = size.width; - var height = size.height; - - if (yAlign === 'center') { - y2 = ptY + (height / 2); - - if (xAlign === 'left') { - x1 = ptX; - x2 = x1 - caretSize; - x3 = x1; - - y1 = y2 + caretSize; - y3 = y2 - caretSize; - } else { - x1 = ptX + width; - x2 = x1 + caretSize; - x3 = x1; - - y1 = y2 - caretSize; - y3 = y2 + caretSize; - } - } else { - if (xAlign === 'left') { - x2 = ptX + cornerRadius + (caretSize); - x1 = x2 - caretSize; - x3 = x2 + caretSize; - } else if (xAlign === 'right') { - x2 = ptX + width - cornerRadius - caretSize; - x1 = x2 - caretSize; - x3 = x2 + caretSize; - } else { - x2 = vm.caretX; - x1 = x2 - caretSize; - x3 = x2 + caretSize; - } - if (yAlign === 'top') { - y1 = ptY; - y2 = y1 - caretSize; - y3 = y1; - } else { - y1 = ptY + height; - y2 = y1 + caretSize; - y3 = y1; - // invert drawing order - var tmp = x3; - x3 = x1; - x1 = tmp; - } - } - return { x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3 }; - }, - drawTitle: function (pt, vm, ctx, opacity) { - var title = vm.title; - - if (title.length) { - ctx.textAlign = vm._titleAlign; - ctx.textBaseline = 'top'; - - var titleFontSize = vm.titleFontSize; - var titleSpacing = vm.titleSpacing; - - ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity); - ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily); - - var i, len; - for (i = 0, len = title.length; i < len; ++i) { - ctx.fillText(title[i], pt.x, pt.y); - pt.y += titleFontSize + titleSpacing; // Line Height and spacing - - if (i + 1 === title.length) { - pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing - } - } - } - }, - drawBody: function (pt, vm, ctx, opacity) { - var bodyFontSize = vm.bodyFontSize; - var bodySpacing = vm.bodySpacing; - var body = vm.body; - - ctx.textAlign = vm._bodyAlign; - ctx.textBaseline = 'top'; - ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); - - // Before Body - var xLinePadding = 0; - var fillLineOfText = function (line) { - ctx.fillText(line, pt.x + xLinePadding, pt.y); - pt.y += bodyFontSize + bodySpacing; - }; - - // Before body lines - ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity); - helpers.each(vm.beforeBody, fillLineOfText); - - var drawColorBoxes = vm.displayColors; - xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0; - - // Draw body lines now - helpers.each(body, function (bodyItem, i) { - var textColor = mergeOpacity(vm.labelTextColors[i], opacity); - ctx.fillStyle = textColor; - helpers.each(bodyItem.before, fillLineOfText); - - helpers.each(bodyItem.lines, function (line) { - // Draw Legend-like boxes if needed - if (drawColorBoxes) { - // Fill a white rect so that colours merge nicely if the opacity is < 1 - ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity); - ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize); - - // Border - ctx.lineWidth = 1; - ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity); - ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize); - - // Inner square - ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity); - ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2); - ctx.fillStyle = textColor; - } - - fillLineOfText(line); - }); - - helpers.each(bodyItem.after, fillLineOfText); - }); - - // Reset back to 0 for after body - xLinePadding = 0; - - // After body lines - helpers.each(vm.afterBody, fillLineOfText); - pt.y -= bodySpacing; // Remove last body spacing - }, - drawFooter: function (pt, vm, ctx, opacity) { - var footer = vm.footer; - - if (footer.length) { - pt.y += vm.footerMarginTop; - - ctx.textAlign = vm._footerAlign; - ctx.textBaseline = 'top'; - - ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity); - ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); - - helpers.each(footer, function (line) { - ctx.fillText(line, pt.x, pt.y); - pt.y += vm.footerFontSize + vm.footerSpacing; - }); - } - }, - drawBackground: function (pt, vm, ctx, tooltipSize, opacity) { - ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity); - ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity); - ctx.lineWidth = vm.borderWidth; - var xAlign = vm.xAlign; - var yAlign = vm.yAlign; - var x = pt.x; - var y = pt.y; - var width = tooltipSize.width; - var height = tooltipSize.height; - var radius = vm.cornerRadius; - - ctx.beginPath(); - ctx.moveTo(x + radius, y); - if (yAlign === 'top') { - this.drawCaret(pt, tooltipSize); - } - ctx.lineTo(x + width - radius, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius); - if (yAlign === 'center' && xAlign === 'right') { - this.drawCaret(pt, tooltipSize); - } - ctx.lineTo(x + width, y + height - radius); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); - if (yAlign === 'bottom') { - this.drawCaret(pt, tooltipSize); - } - ctx.lineTo(x + radius, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius); - if (yAlign === 'center' && xAlign === 'left') { - this.drawCaret(pt, tooltipSize); - } - ctx.lineTo(x, y + radius); - ctx.quadraticCurveTo(x, y, x + radius, y); - ctx.closePath(); - - ctx.fill(); - - if (vm.borderWidth > 0) { - ctx.stroke(); - } - }, - draw: function () { - var ctx = this._chart.ctx; - var vm = this._view; - - if (vm.opacity === 0) { - return; - } - - var tooltipSize = { - width: vm.width, - height: vm.height - }; - var pt = { - x: vm.x, - y: vm.y - }; - - // IE11/Edge does not like very small opacities, so snap to 0 - var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity; - - // Truthy/falsey value for empty tooltip - var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length; - - if (this._options.enabled && hasTooltipContent) { - // Draw Background - this.drawBackground(pt, vm, ctx, tooltipSize, opacity); - - // Draw Title, Body, and Footer - pt.x += vm.xPadding; - pt.y += vm.yPadding; - - // Titles - this.drawTitle(pt, vm, ctx, opacity); - - // Body - this.drawBody(pt, vm, ctx, opacity); - - // Footer - this.drawFooter(pt, vm, ctx, opacity); - } - }, - - /** - * Handle an event - * @private - * @param {IEvent} event - The event to handle - * @returns {Boolean} true if the tooltip changed - */ - handleEvent: function (e) { - var me = this; - var options = me._options; - var changed = false; - - me._lastActive = me._lastActive || []; - - // Find Active Elements for tooltips - if (e.type === 'mouseout') { - me._active = []; - } else { - me._active = me._chart.getElementsAtEventForMode(e, options.mode, options); - } - - // Remember Last Actives - changed = !helpers.arrayEquals(me._active, me._lastActive); - - // Only handle target event on tooltip change - if (changed) { - me._lastActive = me._active; - - if (options.enabled || options.custom) { - me._eventPosition = { - x: e.x, - y: e.y - }; - - me.update(true); - me.pivot(); - } - } - - return changed; - } - }); - - /** - * @namespace Chart.Tooltip.positioners - */ - Chart.Tooltip.positioners = { - /** - * Average mode places the tooltip at the average position of the elements shown - * @function Chart.Tooltip.positioners.average - * @param elements {ChartElement[]} the elements being displayed in the tooltip - * @returns {Point} tooltip position - */ - average: function (elements) { - if (!elements.length) { - return false; - } - - var i, len; - var x = 0; - var y = 0; - var count = 0; - - for (i = 0, len = elements.length; i < len; ++i) { - var el = elements[i]; - if (el && el.hasValue()) { - var pos = el.tooltipPosition(); - x += pos.x; - y += pos.y; - ++count; - } - } - - return { - x: Math.round(x / count), - y: Math.round(y / count) - }; - }, - - /** - * Gets the tooltip position nearest of the item nearest to the event position - * @function Chart.Tooltip.positioners.nearest - * @param elements {Chart.Element[]} the tooltip elements - * @param eventPosition {Point} the position of the event in canvas coordinates - * @returns {Point} the tooltip position - */ - nearest: function (elements, eventPosition) { - var x = eventPosition.x; - var y = eventPosition.y; - var minDistance = Number.POSITIVE_INFINITY; - var i, len, nearestElement; - - for (i = 0, len = elements.length; i < len; ++i) { - var el = elements[i]; - if (el && el.hasValue()) { - var center = el.getCenterPoint(); - var d = helpers.distanceBetweenPoints(eventPosition, center); - - if (d < minDistance) { - minDistance = d; - nearestElement = el; - } - } - } - - if (nearestElement) { - var tp = nearestElement.tooltipPosition(); - x = tp.x; - y = tp.y; - } - - return { - x: x, - y: y - }; - } - }; - }; - - }, { "25": 25, "26": 26, "45": 45 }], 36: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - - defaults._set('global', { - elements: { - arc: { - backgroundColor: defaults.global.defaultColor, - borderColor: '#fff', - borderWidth: 2 - } - } - }); - - module.exports = Element.extend({ - inLabelRange: function (mouseX) { - var vm = this._view; - - if (vm) { - return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2)); - } - return false; - }, - - inRange: function (chartX, chartY) { - var vm = this._view; - - if (vm) { - var pointRelativePosition = helpers.getAngleFromPoint(vm, { x: chartX, y: chartY }); - var angle = pointRelativePosition.angle; - var distance = pointRelativePosition.distance; - - // Sanitise angle range - var startAngle = vm.startAngle; - var endAngle = vm.endAngle; - while (endAngle < startAngle) { - endAngle += 2.0 * Math.PI; - } - while (angle > endAngle) { - angle -= 2.0 * Math.PI; - } - while (angle < startAngle) { - angle += 2.0 * Math.PI; - } - - // Check if within the range of the open/close angle - var betweenAngles = (angle >= startAngle && angle <= endAngle); - var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius); - - return (betweenAngles && withinRadius); - } - return false; - }, - - getCenterPoint: function () { - var vm = this._view; - var halfAngle = (vm.startAngle + vm.endAngle) / 2; - var halfRadius = (vm.innerRadius + vm.outerRadius) / 2; - return { - x: vm.x + Math.cos(halfAngle) * halfRadius, - y: vm.y + Math.sin(halfAngle) * halfRadius - }; - }, - - getArea: function () { - var vm = this._view; - return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2)); - }, - - tooltipPosition: function () { - var vm = this._view; - var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2); - var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius; - - return { - x: vm.x + (Math.cos(centreAngle) * rangeFromCentre), - y: vm.y + (Math.sin(centreAngle) * rangeFromCentre) - }; - }, - - draw: function () { - var ctx = this._chart.ctx; - var vm = this._view; - var sA = vm.startAngle; - var eA = vm.endAngle; - - ctx.beginPath(); - - ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA); - ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true); - - ctx.closePath(); - ctx.strokeStyle = vm.borderColor; - ctx.lineWidth = vm.borderWidth; - - ctx.fillStyle = vm.backgroundColor; - - ctx.fill(); - ctx.lineJoin = 'bevel'; - - if (vm.borderWidth) { - ctx.stroke(); - } - } - }); - - }, { "25": 25, "26": 26, "45": 45 }], 37: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - - var globalDefaults = defaults.global; - - defaults._set('global', { - elements: { - line: { - tension: 0.4, - backgroundColor: globalDefaults.defaultColor, - borderWidth: 3, - borderColor: globalDefaults.defaultColor, - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - capBezierPoints: true, - fill: true, // do we fill in the area between the line and its base axis - } - } - }); - - module.exports = Element.extend({ - draw: function () { - var me = this; - var vm = me._view; - var ctx = me._chart.ctx; - var spanGaps = vm.spanGaps; - var points = me._children.slice(); // clone array - var globalOptionLineElements = globalDefaults.elements.line; - var lastDrawnIndex = -1; - var index, current, previous, currentVM; - - // If we are looping, adding the first point again - if (me._loop && points.length) { - points.push(points[0]); - } - - ctx.save(); - - // Stroke Line Options - ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle; - - // IE 9 and 10 do not support line dash - if (ctx.setLineDash) { - ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash); - } - - ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset; - ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle; - ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth; - ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor; - - // Stroke Line - ctx.beginPath(); - lastDrawnIndex = -1; - - for (index = 0; index < points.length; ++index) { - current = points[index]; - previous = helpers.previousItem(points, index); - currentVM = current._view; - - // First point moves to it's starting position no matter what - if (index === 0) { - if (!currentVM.skip) { - ctx.moveTo(currentVM.x, currentVM.y); - lastDrawnIndex = index; - } - } else { - previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex]; - - if (!currentVM.skip) { - if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) { - // There was a gap and this is the first point after the gap - ctx.moveTo(currentVM.x, currentVM.y); - } else { - // Line to next point - helpers.canvas.lineTo(ctx, previous._view, current._view); - } - lastDrawnIndex = index; - } - } - } - - ctx.stroke(); - ctx.restore(); - } - }); - - }, { "25": 25, "26": 26, "45": 45 }], 38: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - - var defaultColor = defaults.global.defaultColor; - - defaults._set('global', { - elements: { - point: { - radius: 3, - pointStyle: 'circle', - backgroundColor: defaultColor, - borderColor: defaultColor, - borderWidth: 1, - // Hover - hitRadius: 1, - hoverRadius: 4, - hoverBorderWidth: 1 - } - } - }); - - function xRange(mouseX) { - var vm = this._view; - return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false; - } - - function yRange(mouseY) { - var vm = this._view; - return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false; - } - - module.exports = Element.extend({ - inRange: function (mouseX, mouseY) { - var vm = this._view; - return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false; - }, - - inLabelRange: xRange, - inXRange: xRange, - inYRange: yRange, - - getCenterPoint: function () { - var vm = this._view; - return { - x: vm.x, - y: vm.y - }; - }, - - getArea: function () { - return Math.PI * Math.pow(this._view.radius, 2); - }, - - tooltipPosition: function () { - var vm = this._view; - return { - x: vm.x, - y: vm.y, - padding: vm.radius + vm.borderWidth - }; - }, - - draw: function (chartArea) { - var vm = this._view; - var model = this._model; - var ctx = this._chart.ctx; - var pointStyle = vm.pointStyle; - var radius = vm.radius; - var x = vm.x; - var y = vm.y; - var color = helpers.color; - var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.) - var ratio = 0; - - if (vm.skip) { - return; - } - - ctx.strokeStyle = vm.borderColor || defaultColor; - ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); - ctx.fillStyle = vm.backgroundColor || defaultColor; - - // Cliping for Points. - // going out from inner charArea? - if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) { - // Point fade out - if (model.x < chartArea.left) { - ratio = (x - model.x) / (chartArea.left - model.x); - } else if (chartArea.right * errMargin < model.x) { - ratio = (model.x - x) / (model.x - chartArea.right); - } else if (model.y < chartArea.top) { - ratio = (y - model.y) / (chartArea.top - model.y); - } else if (chartArea.bottom * errMargin < model.y) { - ratio = (model.y - y) / (model.y - chartArea.bottom); - } - ratio = Math.round(ratio * 100) / 100; - ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString(); - ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString(); - } - - helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y); - } - }); - - }, { "25": 25, "26": 26, "45": 45 }], 39: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - - defaults._set('global', { - elements: { - rectangle: { - backgroundColor: defaults.global.defaultColor, - borderColor: defaults.global.defaultColor, - borderSkipped: 'bottom', - borderWidth: 0 - } - } - }); - - function isVertical(bar) { - return bar._view.width !== undefined; - } - - /** - * Helper function to get the bounds of the bar regardless of the orientation - * @param bar {Chart.Element.Rectangle} the bar - * @return {Bounds} bounds of the bar - * @private - */ - function getBarBounds(bar) { - var vm = bar._view; - var x1, x2, y1, y2; - - if (isVertical(bar)) { - // vertical - var halfWidth = vm.width / 2; - x1 = vm.x - halfWidth; - x2 = vm.x + halfWidth; - y1 = Math.min(vm.y, vm.base); - y2 = Math.max(vm.y, vm.base); - } else { - // horizontal bar - var halfHeight = vm.height / 2; - x1 = Math.min(vm.x, vm.base); - x2 = Math.max(vm.x, vm.base); - y1 = vm.y - halfHeight; - y2 = vm.y + halfHeight; - } - - return { - left: x1, - top: y1, - right: x2, - bottom: y2 - }; - } - - module.exports = Element.extend({ - draw: function () { - var ctx = this._chart.ctx; - var vm = this._view; - var left, right, top, bottom, signX, signY, borderSkipped; - var borderWidth = vm.borderWidth; - - if (!vm.horizontal) { - // bar - left = vm.x - vm.width / 2; - right = vm.x + vm.width / 2; - top = vm.y; - bottom = vm.base; - signX = 1; - signY = bottom > top ? 1 : -1; - borderSkipped = vm.borderSkipped || 'bottom'; - } else { - // horizontal bar - left = vm.base; - right = vm.x; - top = vm.y - vm.height / 2; - bottom = vm.y + vm.height / 2; - signX = right > left ? 1 : -1; - signY = 1; - borderSkipped = vm.borderSkipped || 'left'; - } - - // Canvas doesn't allow us to stroke inside the width so we can - // adjust the sizes to fit if we're setting a stroke on the line - if (borderWidth) { - // borderWidth shold be less than bar width and bar height. - var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom)); - borderWidth = borderWidth > barSize ? barSize : borderWidth; - var halfStroke = borderWidth / 2; - // Adjust borderWidth when bar top position is near vm.base(zero). - var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0); - var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0); - var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0); - var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0); - // not become a vertical line? - if (borderLeft !== borderRight) { - top = borderTop; - bottom = borderBottom; - } - // not become a horizontal line? - if (borderTop !== borderBottom) { - left = borderLeft; - right = borderRight; - } - } - - ctx.beginPath(); - ctx.fillStyle = vm.backgroundColor; - ctx.strokeStyle = vm.borderColor; - ctx.lineWidth = borderWidth; - - // Corner points, from bottom-left to bottom-right clockwise - // | 1 2 | - // | 0 3 | - var corners = [ - [left, bottom], - [left, top], - [right, top], - [right, bottom] - ]; - - // Find first (starting) corner with fallback to 'bottom' - var borders = ['bottom', 'left', 'top', 'right']; - var startCorner = borders.indexOf(borderSkipped, 0); - if (startCorner === -1) { - startCorner = 0; - } - - function cornerAt(index) { - return corners[(startCorner + index) % 4]; - } - - // Draw rectangle from 'startCorner' - var corner = cornerAt(0); - ctx.moveTo(corner[0], corner[1]); - - for (var i = 1; i < 4; i++) { - corner = cornerAt(i); - ctx.lineTo(corner[0], corner[1]); - } - - ctx.fill(); - if (borderWidth) { - ctx.stroke(); - } - }, - - height: function () { - var vm = this._view; - return vm.base - vm.y; - }, - - inRange: function (mouseX, mouseY) { - var inRange = false; - - if (this._view) { - var bounds = getBarBounds(this); - inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom; - } - - return inRange; - }, - - inLabelRange: function (mouseX, mouseY) { - var me = this; - if (!me._view) { - return false; - } - - var inRange = false; - var bounds = getBarBounds(me); - - if (isVertical(me)) { - inRange = mouseX >= bounds.left && mouseX <= bounds.right; - } else { - inRange = mouseY >= bounds.top && mouseY <= bounds.bottom; - } - - return inRange; - }, - - inXRange: function (mouseX) { - var bounds = getBarBounds(this); - return mouseX >= bounds.left && mouseX <= bounds.right; - }, - - inYRange: function (mouseY) { - var bounds = getBarBounds(this); - return mouseY >= bounds.top && mouseY <= bounds.bottom; - }, - - getCenterPoint: function () { - var vm = this._view; - var x, y; - if (isVertical(this)) { - x = vm.x; - y = (vm.y + vm.base) / 2; - } else { - x = (vm.x + vm.base) / 2; - y = vm.y; - } - - return { x: x, y: y }; - }, - - getArea: function () { - var vm = this._view; - return vm.width * Math.abs(vm.y - vm.base); - }, - - tooltipPosition: function () { - var vm = this._view; - return { - x: vm.x, - y: vm.y - }; - } - }); - - }, { "25": 25, "26": 26 }], 40: [function (require, module, exports) { - 'use strict'; - - module.exports = {}; - module.exports.Arc = require(36); - module.exports.Line = require(37); - module.exports.Point = require(38); - module.exports.Rectangle = require(39); - - }, { "36": 36, "37": 37, "38": 38, "39": 39 }], 41: [function (require, module, exports) { - 'use strict'; - - var helpers = require(42); - - /** - * @namespace Chart.helpers.canvas - */ - var exports = module.exports = { - /** - * Clears the entire canvas associated to the given `chart`. - * @param {Chart} chart - The chart for which to clear the canvas. - */ - clear: function (chart) { - chart.ctx.clearRect(0, 0, chart.width, chart.height); - }, - - /** - * Creates a "path" for a rectangle with rounded corners at position (x, y) with a - * given size (width, height) and the same `radius` for all corners. - * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context. - * @param {Number} x - The x axis of the coordinate for the rectangle starting point. - * @param {Number} y - The y axis of the coordinate for the rectangle starting point. - * @param {Number} width - The rectangle's width. - * @param {Number} height - The rectangle's height. - * @param {Number} radius - The rounded amount (in pixels) for the four corners. - * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object? - */ - roundedRect: function (ctx, x, y, width, height, radius) { - if (radius) { - var rx = Math.min(radius, width / 2); - var ry = Math.min(radius, height / 2); - - ctx.moveTo(x + rx, y); - ctx.lineTo(x + width - rx, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + ry); - ctx.lineTo(x + width, y + height - ry); - ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height); - ctx.lineTo(x + rx, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - ry); - ctx.lineTo(x, y + ry); - ctx.quadraticCurveTo(x, y, x + rx, y); - } else { - ctx.rect(x, y, width, height); - } - }, - - drawPoint: function (ctx, style, radius, x, y) { - var type, edgeLength, xOffset, yOffset, height, size; - - if (style && typeof style === 'object') { - type = style.toString(); - if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { - ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height); - return; - } - } - - if (isNaN(radius) || radius <= 0) { - return; - } - - switch (style) { - // Default includes circle - default: - ctx.beginPath(); - ctx.arc(x, y, radius, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); - break; - case 'triangle': - ctx.beginPath(); - edgeLength = 3 * radius / Math.sqrt(3); - height = edgeLength * Math.sqrt(3) / 2; - ctx.moveTo(x - edgeLength / 2, y + height / 3); - ctx.lineTo(x + edgeLength / 2, y + height / 3); - ctx.lineTo(x, y - 2 * height / 3); - ctx.closePath(); - ctx.fill(); - break; - case 'rect': - size = 1 / Math.SQRT2 * radius; - ctx.beginPath(); - ctx.fillRect(x - size, y - size, 2 * size, 2 * size); - ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); - break; - case 'rectRounded': - var offset = radius / Math.SQRT2; - var leftX = x - offset; - var topY = y - offset; - var sideSize = Math.SQRT2 * radius; - ctx.beginPath(); - this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2); - ctx.closePath(); - ctx.fill(); - break; - case 'rectRot': - size = 1 / Math.SQRT2 * radius; - ctx.beginPath(); - ctx.moveTo(x - size, y); - ctx.lineTo(x, y + size); - ctx.lineTo(x + size, y); - ctx.lineTo(x, y - size); - ctx.closePath(); - ctx.fill(); - break; - case 'cross': - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); - break; - case 'crossRot': - ctx.beginPath(); - xOffset = Math.cos(Math.PI / 4) * radius; - yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); - ctx.closePath(); - break; - case 'star': - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - xOffset = Math.cos(Math.PI / 4) * radius; - yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); - ctx.closePath(); - break; - case 'line': - ctx.beginPath(); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); - break; - case 'dash': - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); - break; - } - - ctx.stroke(); - }, - - clipArea: function (ctx, area) { - ctx.save(); - ctx.beginPath(); - ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); - ctx.clip(); - }, - - unclipArea: function (ctx) { - ctx.restore(); - }, - - lineTo: function (ctx, previous, target, flip) { - if (target.steppedLine) { - if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) { - ctx.lineTo(previous.x, target.y); - } else { - ctx.lineTo(target.x, previous.y); - } - ctx.lineTo(target.x, target.y); - return; - } - - if (!target.tension) { - ctx.lineTo(target.x, target.y); - return; - } - - ctx.bezierCurveTo( - flip ? previous.controlPointPreviousX : previous.controlPointNextX, - flip ? previous.controlPointPreviousY : previous.controlPointNextY, - flip ? target.controlPointNextX : target.controlPointPreviousX, - flip ? target.controlPointNextY : target.controlPointPreviousY, - target.x, - target.y); - } - }; - - // DEPRECATIONS - - /** - * Provided for backward compatibility, use Chart.helpers.canvas.clear instead. - * @namespace Chart.helpers.clear - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.clear = exports.clear; - - /** - * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead. - * @namespace Chart.helpers.drawRoundedRectangle - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.drawRoundedRectangle = function (ctx) { - ctx.beginPath(); - exports.roundedRect.apply(exports, arguments); - ctx.closePath(); - }; - - }, { "42": 42 }], 42: [function (require, module, exports) { - 'use strict'; - - /** - * @namespace Chart.helpers - */ - var helpers = { - /** - * An empty function that can be used, for example, for optional callback. - */ - noop: function () { }, - - /** - * Returns a unique id, sequentially generated from a global variable. - * @returns {Number} - * @function - */ - uid: (function () { - var id = 0; - return function () { - return id++; - }; - } ()), - - /** - * Returns true if `value` is neither null nor undefined, else returns false. - * @param {*} value - The value to test. - * @returns {Boolean} - * @since 2.7.0 - */ - isNullOrUndef: function (value) { - return value === null || typeof value === 'undefined'; - }, - - /** - * Returns true if `value` is an array, else returns false. - * @param {*} value - The value to test. - * @returns {Boolean} - * @function - */ - isArray: Array.isArray ? Array.isArray : function (value) { - return Object.prototype.toString.call(value) === '[object Array]'; - }, - - /** - * Returns true if `value` is an object (excluding null), else returns false. - * @param {*} value - The value to test. - * @returns {Boolean} - * @since 2.7.0 - */ - isObject: function (value) { - return value !== null && Object.prototype.toString.call(value) === '[object Object]'; - }, - - /** - * Returns `value` if defined, else returns `defaultValue`. - * @param {*} value - The value to return if defined. - * @param {*} defaultValue - The value to return if `value` is undefined. - * @returns {*} - */ - valueOrDefault: function (value, defaultValue) { - return typeof value === 'undefined' ? defaultValue : value; - }, - - /** - * Returns value at the given `index` in array if defined, else returns `defaultValue`. - * @param {Array} value - The array to lookup for value at `index`. - * @param {Number} index - The index in `value` to lookup for value. - * @param {*} defaultValue - The value to return if `value[index]` is undefined. - * @returns {*} - */ - valueAtIndexOrDefault: function (value, index, defaultValue) { - return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue); - }, - - /** - * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the - * value returned by `fn`. If `fn` is not a function, this method returns undefined. - * @param {Function} fn - The function to call. - * @param {Array|undefined|null} args - The arguments with which `fn` should be called. - * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`. - * @returns {*} - */ - callback: function (fn, args, thisArg) { - if (fn && typeof fn.call === 'function') { - return fn.apply(thisArg, args); - } - }, - - /** - * Note(SB) for performance sake, this method should only be used when loopable type - * is unknown or in none intensive code (not called often and small loopable). Else - * it's preferable to use a regular for() loop and save extra function calls. - * @param {Object|Array} loopable - The object or array to be iterated. - * @param {Function} fn - The function to call for each item. - * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`. - * @param {Boolean} [reverse] - If true, iterates backward on the loopable. - */ - each: function (loopable, fn, thisArg, reverse) { - var i, len, keys; - if (helpers.isArray(loopable)) { - len = loopable.length; - if (reverse) { - for (i = len - 1; i >= 0; i--) { - fn.call(thisArg, loopable[i], i); - } - } else { - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[i], i); - } - } - } else if (helpers.isObject(loopable)) { - keys = Object.keys(loopable); - len = keys.length; - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[keys[i]], keys[i]); - } - } - }, - - /** - * Returns true if the `a0` and `a1` arrays have the same content, else returns false. - * @see http://stackoverflow.com/a/14853974 - * @param {Array} a0 - The array to compare - * @param {Array} a1 - The array to compare - * @returns {Boolean} - */ - arrayEquals: function (a0, a1) { - var i, ilen, v0, v1; - - if (!a0 || !a1 || a0.length !== a1.length) { - return false; - } - - for (i = 0, ilen = a0.length; i < ilen; ++i) { - v0 = a0[i]; - v1 = a1[i]; - - if (v0 instanceof Array && v1 instanceof Array) { - if (!helpers.arrayEquals(v0, v1)) { - return false; - } - } else if (v0 !== v1) { - // NOTE: two different object instances will never be equal: {x:20} != {x:20} - return false; - } - } - - return true; - }, - - /** - * Returns a deep copy of `source` without keeping references on objects and arrays. - * @param {*} source - The value to clone. - * @returns {*} - */ - clone: function (source) { - if (helpers.isArray(source)) { - return source.map(helpers.clone); - } - - if (helpers.isObject(source)) { - var target = {}; - var keys = Object.keys(source); - var klen = keys.length; - var k = 0; - - for (; k < klen; ++k) { - target[keys[k]] = helpers.clone(source[keys[k]]); - } - - return target; - } - - return source; - }, - - /** - * The default merger when Chart.helpers.merge is called without merger option. - * Note(SB): this method is also used by configMerge and scaleMerge as fallback. - * @private - */ - _merger: function (key, target, source, options) { - var tval = target[key]; - var sval = source[key]; - - if (helpers.isObject(tval) && helpers.isObject(sval)) { - helpers.merge(tval, sval, options); - } else { - target[key] = helpers.clone(sval); - } - }, - - /** - * Merges source[key] in target[key] only if target[key] is undefined. - * @private - */ - _mergerIf: function (key, target, source) { - var tval = target[key]; - var sval = source[key]; - - if (helpers.isObject(tval) && helpers.isObject(sval)) { - helpers.mergeIf(tval, sval); - } else if (!target.hasOwnProperty(key)) { - target[key] = helpers.clone(sval); - } - }, - - /** - * Recursively deep copies `source` properties into `target` with the given `options`. - * IMPORTANT: `target` is not cloned and will be updated with `source` properties. - * @param {Object} target - The target object in which all sources are merged into. - * @param {Object|Array(Object)} source - Object(s) to merge into `target`. - * @param {Object} [options] - Merging options: - * @param {Function} [options.merger] - The merge method (key, target, source, options) - * @returns {Object} The `target` object. - */ - merge: function (target, source, options) { - var sources = helpers.isArray(source) ? source : [source]; - var ilen = sources.length; - var merge, i, keys, klen, k; - - if (!helpers.isObject(target)) { - return target; - } - - options = options || {}; - merge = options.merger || helpers._merger; - - for (i = 0; i < ilen; ++i) { - source = sources[i]; - if (!helpers.isObject(source)) { - continue; - } - - keys = Object.keys(source); - for (k = 0, klen = keys.length; k < klen; ++k) { - merge(keys[k], target, source, options); - } - } - - return target; - }, - - /** - * Recursively deep copies `source` properties into `target` *only* if not defined in target. - * IMPORTANT: `target` is not cloned and will be updated with `source` properties. - * @param {Object} target - The target object in which all sources are merged into. - * @param {Object|Array(Object)} source - Object(s) to merge into `target`. - * @returns {Object} The `target` object. - */ - mergeIf: function (target, source) { - return helpers.merge(target, source, { merger: helpers._mergerIf }); - }, - - /** - * Applies the contents of two or more objects together into the first object. - * @param {Object} target - The target object in which all objects are merged into. - * @param {Object} arg1 - Object containing additional properties to merge in target. - * @param {Object} argN - Additional objects containing properties to merge in target. - * @returns {Object} The `target` object. - */ - extend: function (target) { - var setFn = function (value, key) { - target[key] = value; - }; - for (var i = 1, ilen = arguments.length; i < ilen; ++i) { - helpers.each(arguments[i], setFn); - } - return target; - }, - - /** - * Basic javascript inheritance based on the model created in Backbone.js - */ - inherits: function (extensions) { - var me = this; - var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function () { - return me.apply(this, arguments); - }; - - var Surrogate = function () { - this.constructor = ChartElement; - }; - - Surrogate.prototype = me.prototype; - ChartElement.prototype = new Surrogate(); - ChartElement.extend = helpers.inherits; - - if (extensions) { - helpers.extend(ChartElement.prototype, extensions); - } - - ChartElement.__super__ = me.prototype; - return ChartElement; - } - }; - - module.exports = helpers; - - // DEPRECATIONS - - /** - * Provided for backward compatibility, use Chart.helpers.callback instead. - * @function Chart.helpers.callCallback - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ - helpers.callCallback = helpers.callback; - - /** - * Provided for backward compatibility, use Array.prototype.indexOf instead. - * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+ - * @function Chart.helpers.indexOf - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.indexOf = function (array, item, fromIndex) { - return Array.prototype.indexOf.call(array, item, fromIndex); - }; - - /** - * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead. - * @function Chart.helpers.getValueOrDefault - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.getValueOrDefault = helpers.valueOrDefault; - - /** - * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead. - * @function Chart.helpers.getValueAtIndexOrDefault - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault; - - }, {}], 43: [function (require, module, exports) { - 'use strict'; - - var helpers = require(42); - - /** - * Easing functions adapted from Robert Penner's easing equations. - * @namespace Chart.helpers.easingEffects - * @see http://www.robertpenner.com/easing/ - */ - var effects = { - linear: function (t) { - return t; - }, - - easeInQuad: function (t) { - return t * t; - }, - - easeOutQuad: function (t) { - return -t * (t - 2); - }, - - easeInOutQuad: function (t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t; - } - return -0.5 * ((--t) * (t - 2) - 1); - }, - - easeInCubic: function (t) { - return t * t * t; - }, - - easeOutCubic: function (t) { - return (t = t - 1) * t * t + 1; - }, - - easeInOutCubic: function (t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t * t; - } - return 0.5 * ((t -= 2) * t * t + 2); - }, - - easeInQuart: function (t) { - return t * t * t * t; - }, - - easeOutQuart: function (t) { - return -((t = t - 1) * t * t * t - 1); - }, - - easeInOutQuart: function (t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t * t * t; - } - return -0.5 * ((t -= 2) * t * t * t - 2); - }, - - easeInQuint: function (t) { - return t * t * t * t * t; - }, - - easeOutQuint: function (t) { - return (t = t - 1) * t * t * t * t + 1; - }, - - easeInOutQuint: function (t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t * t * t * t; - } - return 0.5 * ((t -= 2) * t * t * t * t + 2); - }, - - easeInSine: function (t) { - return -Math.cos(t * (Math.PI / 2)) + 1; - }, - - easeOutSine: function (t) { - return Math.sin(t * (Math.PI / 2)); - }, - - easeInOutSine: function (t) { - return -0.5 * (Math.cos(Math.PI * t) - 1); - }, - - easeInExpo: function (t) { - return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)); - }, - - easeOutExpo: function (t) { - return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1; - }, - - easeInOutExpo: function (t) { - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - if ((t /= 0.5) < 1) { - return 0.5 * Math.pow(2, 10 * (t - 1)); - } - return 0.5 * (-Math.pow(2, -10 * --t) + 2); - }, - - easeInCirc: function (t) { - if (t >= 1) { - return t; - } - return -(Math.sqrt(1 - t * t) - 1); - }, - - easeOutCirc: function (t) { - return Math.sqrt(1 - (t = t - 1) * t); - }, - - easeInOutCirc: function (t) { - if ((t /= 0.5) < 1) { - return -0.5 * (Math.sqrt(1 - t * t) - 1); - } - return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); - }, - - easeInElastic: function (t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - if (!p) { - p = 0.3; - } - if (a < 1) { - a = 1; - s = p / 4; - } else { - s = p / (2 * Math.PI) * Math.asin(1 / a); - } - return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); - }, - - easeOutElastic: function (t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - if (!p) { - p = 0.3; - } - if (a < 1) { - a = 1; - s = p / 4; - } else { - s = p / (2 * Math.PI) * Math.asin(1 / a); - } - return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1; - }, - - easeInOutElastic: function (t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) { - return 0; - } - if ((t /= 0.5) === 2) { - return 1; - } - if (!p) { - p = 0.45; - } - if (a < 1) { - a = 1; - s = p / 4; - } else { - s = p / (2 * Math.PI) * Math.asin(1 / a); - } - if (t < 1) { - return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); - } - return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1; - }, - easeInBack: function (t) { - var s = 1.70158; - return t * t * ((s + 1) * t - s); - }, - - easeOutBack: function (t) { - var s = 1.70158; - return (t = t - 1) * t * ((s + 1) * t + s) + 1; - }, - - easeInOutBack: function (t) { - var s = 1.70158; - if ((t /= 0.5) < 1) { - return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); - } - return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); - }, - - easeInBounce: function (t) { - return 1 - effects.easeOutBounce(1 - t); - }, - - easeOutBounce: function (t) { - if (t < (1 / 2.75)) { - return 7.5625 * t * t; - } - if (t < (2 / 2.75)) { - return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; - } - if (t < (2.5 / 2.75)) { - return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; - } - return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; - }, - - easeInOutBounce: function (t) { - if (t < 0.5) { - return effects.easeInBounce(t * 2) * 0.5; - } - return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5; - } - }; - - module.exports = { - effects: effects - }; - - // DEPRECATIONS - - /** - * Provided for backward compatibility, use Chart.helpers.easing.effects instead. - * @function Chart.helpers.easingEffects - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.easingEffects = effects; - - }, { "42": 42 }], 44: [function (require, module, exports) { - 'use strict'; - - var helpers = require(42); - - /** - * @alias Chart.helpers.options - * @namespace - */ - module.exports = { - /** - * Converts the given line height `value` in pixels for a specific font `size`. - * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). - * @param {Number} size - The font size (in pixels) used to resolve relative `value`. - * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid). - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height - * @since 2.7.0 - */ - toLineHeight: function (value, size) { - var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); - if (!matches || matches[1] === 'normal') { - return size * 1.2; - } - - value = +matches[2]; - - switch (matches[3]) { - case 'px': - return value; - case '%': - value /= 100; - break; - default: - break; - } - - return size * value; - }, - - /** - * Converts the given value into a padding object with pre-computed width/height. - * @param {Number|Object} value - If a number, set the value to all TRBL component, - * else, if and object, use defined properties and sets undefined ones to 0. - * @returns {Object} The padding values (top, right, bottom, left, width, height) - * @since 2.7.0 - */ - toPadding: function (value) { - var t, r, b, l; - - if (helpers.isObject(value)) { - t = +value.top || 0; - r = +value.right || 0; - b = +value.bottom || 0; - l = +value.left || 0; - } else { - t = r = b = l = +value || 0; - } - - return { - top: t, - right: r, - bottom: b, - left: l, - height: t + b, - width: l + r - }; - }, - - /** - * Evaluates the given `inputs` sequentially and returns the first defined value. - * @param {Array[]} inputs - An array of values, falling back to the last value. - * @param {Object} [context] - If defined and the current value is a function, the value - * is called with `context` as first argument and the result becomes the new input. - * @param {Number} [index] - If defined and the current value is an array, the value - * at `index` become the new input. - * @since 2.7.0 - */ - resolve: function (inputs, context, index) { - var i, ilen, value; - - for (i = 0, ilen = inputs.length; i < ilen; ++i) { - value = inputs[i]; - if (value === undefined) { - continue; - } - if (context !== undefined && typeof value === 'function') { - value = value(context); - } - if (index !== undefined && helpers.isArray(value)) { - value = value[index]; - } - if (value !== undefined) { - return value; - } - } - } - }; - - }, { "42": 42 }], 45: [function (require, module, exports) { - 'use strict'; - - module.exports = require(42); - module.exports.easing = require(43); - module.exports.canvas = require(41); - module.exports.options = require(44); - - }, { "41": 41, "42": 42, "43": 43, "44": 44 }], 46: [function (require, module, exports) { - /** - * Platform fallback implementation (minimal). - * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939 - */ - - module.exports = { - acquireContext: function (item) { - if (item && item.canvas) { - // Support for any object associated to a canvas (including a context2d) - item = item.canvas; - } - - return item && item.getContext('2d') || null; - } - }; - - }, {}], 47: [function (require, module, exports) { - /** - * Chart.Platform implementation for targeting a web browser - */ - - 'use strict'; - - var helpers = require(45); - - var EXPANDO_KEY = '$chartjs'; - var CSS_PREFIX = 'chartjs-'; - var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor'; - var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation'; - var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart']; - - /** - * DOM event types -> Chart.js event types. - * Note: only events with different types are mapped. - * @see https://developer.mozilla.org/en-US/docs/Web/Events - */ - var EVENT_TYPES = { - touchstart: 'mousedown', - touchmove: 'mousemove', - touchend: 'mouseup', - pointerenter: 'mouseenter', - pointerdown: 'mousedown', - pointermove: 'mousemove', - pointerup: 'mouseup', - pointerleave: 'mouseout', - pointerout: 'mouseout' - }; - - /** - * The "used" size is the final value of a dimension property after all calculations have - * been performed. This method uses the computed style of `element` but returns undefined - * if the computed style is not expressed in pixels. That can happen in some cases where - * `element` has a size relative to its parent and this last one is not yet displayed, - * for example because of `display: none` on a parent node. - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value - * @returns {Number} Size in pixels or undefined if unknown. - */ - function readUsedSize(element, property) { - var value = helpers.getStyle(element, property); - var matches = value && value.match(/^(\d+)(\.\d+)?px$/); - return matches ? Number(matches[1]) : undefined; - } - - /** - * Initializes the canvas style and render size without modifying the canvas display size, - * since responsiveness is handled by the controller.resize() method. The config is used - * to determine the aspect ratio to apply in case no explicit height has been specified. - */ - function initCanvas(canvas, config) { - var style = canvas.style; - - // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it - // returns null or '' if no explicit value has been set to the canvas attribute. - var renderHeight = canvas.getAttribute('height'); - var renderWidth = canvas.getAttribute('width'); - - // Chart.js modifies some canvas values that we want to restore on destroy - canvas[EXPANDO_KEY] = { - initial: { - height: renderHeight, - width: renderWidth, - style: { - display: style.display, - height: style.height, - width: style.width - } - } - }; - - // Force canvas to display as block to avoid extra space caused by inline - // elements, which would interfere with the responsive resize process. - // https://github.com/chartjs/Chart.js/issues/2538 - style.display = style.display || 'block'; - - if (renderWidth === null || renderWidth === '') { - var displayWidth = readUsedSize(canvas, 'width'); - if (displayWidth !== undefined) { - canvas.width = displayWidth; - } - } - - if (renderHeight === null || renderHeight === '') { - if (canvas.style.height === '') { - // If no explicit render height and style height, let's apply the aspect ratio, - // which one can be specified by the user but also by charts as default option - // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2. - canvas.height = canvas.width / (config.options.aspectRatio || 2); - } else { - var displayHeight = readUsedSize(canvas, 'height'); - if (displayWidth !== undefined) { - canvas.height = displayHeight; - } - } - } - - return canvas; - } - - /** - * Detects support for options object argument in addEventListener. - * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support - * @private - */ - var supportsEventListenerOptions = (function () { - var supports = false; - try { - var options = Object.defineProperty({}, 'passive', { - get: function () { - supports = true; - } - }); - window.addEventListener('e', null, options); - } catch (e) { - // continue regardless of error - } - return supports; - } ()); - - // Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events. - // https://github.com/chartjs/Chart.js/issues/4287 - var eventListenerOptions = supportsEventListenerOptions ? { passive: true } : false; - - function addEventListener(node, type, listener) { - node.addEventListener(type, listener, eventListenerOptions); - } - - function removeEventListener(node, type, listener) { - node.removeEventListener(type, listener, eventListenerOptions); - } - - function createEvent(type, chart, x, y, nativeEvent) { - return { - type: type, - chart: chart, - native: nativeEvent || null, - x: x !== undefined ? x : null, - y: y !== undefined ? y : null, - }; - } - - function fromNativeEvent(event, chart) { - var type = EVENT_TYPES[event.type] || event.type; - var pos = helpers.getRelativePosition(event, chart); - return createEvent(type, chart, pos.x, pos.y, event); - } - - function throttled(fn, thisArg) { - var ticking = false; - var args = []; - - return function () { - args = Array.prototype.slice.call(arguments); - thisArg = thisArg || this; - - if (!ticking) { - ticking = true; - helpers.requestAnimFrame.call(window, function () { - ticking = false; - fn.apply(thisArg, args); - }); - } - }; - } - - // Implementation based on https://github.com/marcj/css-element-queries - function createResizer(handler) { - var resizer = document.createElement('div'); - var cls = CSS_PREFIX + 'size-monitor'; - var maxSize = 1000000; - var style = - 'position:absolute;' + - 'left:0;' + - 'top:0;' + - 'right:0;' + - 'bottom:0;' + - 'overflow:hidden;' + - 'pointer-events:none;' + - 'visibility:hidden;' + - 'z-index:-1;'; - - resizer.style.cssText = style; - resizer.className = cls; - resizer.innerHTML = - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
'; - - var expand = resizer.childNodes[0]; - var shrink = resizer.childNodes[1]; - - resizer._reset = function () { - expand.scrollLeft = maxSize; - expand.scrollTop = maxSize; - shrink.scrollLeft = maxSize; - shrink.scrollTop = maxSize; - }; - var onScroll = function () { - resizer._reset(); - handler(); - }; - - addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand')); - addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink')); - - return resizer; - } - - // https://davidwalsh.name/detect-node-insertion - function watchForRender(node, handler) { - var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {}); - var proxy = expando.renderProxy = function (e) { - if (e.animationName === CSS_RENDER_ANIMATION) { - handler(); - } - }; - - helpers.each(ANIMATION_START_EVENTS, function (type) { - addEventListener(node, type, proxy); - }); - - // #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class - // is removed then added back immediately (same animation frame?). Accessing the - // `offsetParent` property will force a reflow and re-evaluate the CSS animation. - // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics - // https://github.com/chartjs/Chart.js/issues/4737 - expando.reflow = !!node.offsetParent; - - node.classList.add(CSS_RENDER_MONITOR); - } - - function unwatchForRender(node) { - var expando = node[EXPANDO_KEY] || {}; - var proxy = expando.renderProxy; - - if (proxy) { - helpers.each(ANIMATION_START_EVENTS, function (type) { - removeEventListener(node, type, proxy); - }); - - delete expando.renderProxy; - } - - node.classList.remove(CSS_RENDER_MONITOR); - } - - function addResizeListener(node, listener, chart) { - var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {}); - - // Let's keep track of this added resizer and thus avoid DOM query when removing it. - var resizer = expando.resizer = createResizer(throttled(function () { - if (expando.resizer) { - return listener(createEvent('resize', chart)); - } - })); - - // The resizer needs to be attached to the node parent, so we first need to be - // sure that `node` is attached to the DOM before injecting the resizer element. - watchForRender(node, function () { - if (expando.resizer) { - var container = node.parentNode; - if (container && container !== resizer.parentNode) { - container.insertBefore(resizer, container.firstChild); - } - - // The container size might have changed, let's reset the resizer state. - resizer._reset(); - } - }); - } - - function removeResizeListener(node) { - var expando = node[EXPANDO_KEY] || {}; - var resizer = expando.resizer; - - delete expando.resizer; - unwatchForRender(node); - - if (resizer && resizer.parentNode) { - resizer.parentNode.removeChild(resizer); - } - } - - function injectCSS(platform, css) { - // http://stackoverflow.com/q/3922139 - var style = platform._style || document.createElement('style'); - if (!platform._style) { - platform._style = style; - css = '/* Chart.js */\n' + css; - style.setAttribute('type', 'text/css'); - document.getElementsByTagName('head')[0].appendChild(style); - } - - style.appendChild(document.createTextNode(css)); - } - - module.exports = { - /** - * This property holds whether this platform is enabled for the current environment. - * Currently used by platform.js to select the proper implementation. - * @private - */ - _enabled: typeof window !== 'undefined' && typeof document !== 'undefined', - - initialize: function () { - var keyframes = 'from{opacity:0.99}to{opacity:1}'; - - injectCSS(this, - // DOM rendering detection - // https://davidwalsh.name/detect-node-insertion - '@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' + - '@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' + - '.' + CSS_RENDER_MONITOR + '{' + - '-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' + - 'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' + - '}' - ); - }, - - acquireContext: function (item, config) { - if (typeof item === 'string') { - item = document.getElementById(item); - } else if (item.length) { - // Support for array based queries (such as jQuery) - item = item[0]; - } - - if (item && item.canvas) { - // Support for any object associated to a canvas (including a context2d) - item = item.canvas; - } - - // To prevent canvas fingerprinting, some add-ons undefine the getContext - // method, for example: https://github.com/kkapsner/CanvasBlocker - // https://github.com/chartjs/Chart.js/issues/2807 - var context = item && item.getContext && item.getContext('2d'); - - // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is - // inside an iframe or when running in a protected environment. We could guess the - // types from their toString() value but let's keep things flexible and assume it's - // a sufficient condition if the item has a context2D which has item as `canvas`. - // https://github.com/chartjs/Chart.js/issues/3887 - // https://github.com/chartjs/Chart.js/issues/4102 - // https://github.com/chartjs/Chart.js/issues/4152 - if (context && context.canvas === item) { - initCanvas(item, config); - return context; - } - - return null; - }, - - releaseContext: function (context) { - var canvas = context.canvas; - if (!canvas[EXPANDO_KEY]) { - return; - } - - var initial = canvas[EXPANDO_KEY].initial; - ['height', 'width'].forEach(function (prop) { - var value = initial[prop]; - if (helpers.isNullOrUndef(value)) { - canvas.removeAttribute(prop); - } else { - canvas.setAttribute(prop, value); - } - }); - - helpers.each(initial.style || {}, function (value, key) { - canvas.style[key] = value; - }); - - // The canvas render size might have been changed (and thus the state stack discarded), - // we can't use save() and restore() to restore the initial state. So make sure that at - // least the canvas context is reset to the default state by setting the canvas width. - // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html - canvas.width = canvas.width; - - delete canvas[EXPANDO_KEY]; - }, - - addEventListener: function (chart, type, listener) { - var canvas = chart.canvas; - if (type === 'resize') { - // Note: the resize event is not supported on all browsers. - addResizeListener(canvas, listener, chart); - return; - } - - var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {}); - var proxies = expando.proxies || (expando.proxies = {}); - var proxy = proxies[chart.id + '_' + type] = function (event) { - listener(fromNativeEvent(event, chart)); - }; - - addEventListener(canvas, type, proxy); - }, - - removeEventListener: function (chart, type, listener) { - var canvas = chart.canvas; - if (type === 'resize') { - // Note: the resize event is not supported on all browsers. - removeResizeListener(canvas, listener); - return; - } - - var expando = listener[EXPANDO_KEY] || {}; - var proxies = expando.proxies || {}; - var proxy = proxies[chart.id + '_' + type]; - if (!proxy) { - return; - } - - removeEventListener(canvas, type, proxy); - } - }; - - // DEPRECATIONS - - /** - * Provided for backward compatibility, use EventTarget.addEventListener instead. - * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+ - * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener - * @function Chart.helpers.addEvent - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.addEvent = addEventListener; - - /** - * Provided for backward compatibility, use EventTarget.removeEventListener instead. - * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+ - * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener - * @function Chart.helpers.removeEvent - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ - helpers.removeEvent = removeEventListener; - - }, { "45": 45 }], 48: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - var basic = require(46); - var dom = require(47); - - // @TODO Make possible to select another platform at build time. - var implementation = dom._enabled ? dom : basic; - - /** - * @namespace Chart.platform - * @see https://chartjs.gitbooks.io/proposals/content/Platform.html - * @since 2.4.0 - */ - module.exports = helpers.extend({ - /** - * @since 2.7.0 - */ - initialize: function () { }, - - /** - * Called at chart construction time, returns a context2d instance implementing - * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}. - * @param {*} item - The native item from which to acquire context (platform specific) - * @param {Object} options - The chart options - * @returns {CanvasRenderingContext2D} context2d instance - */ - acquireContext: function () { }, - - /** - * Called at chart destruction time, releases any resources associated to the context - * previously returned by the acquireContext() method. - * @param {CanvasRenderingContext2D} context - The context2d instance - * @returns {Boolean} true if the method succeeded, else false - */ - releaseContext: function () { }, - - /** - * Registers the specified listener on the given chart. - * @param {Chart} chart - Chart from which to listen for event - * @param {String} type - The ({@link IEvent}) type to listen for - * @param {Function} listener - Receives a notification (an object that implements - * the {@link IEvent} interface) when an event of the specified type occurs. - */ - addEventListener: function () { }, - - /** - * Removes the specified listener previously registered with addEventListener. - * @param {Chart} chart -Chart from which to remove the listener - * @param {String} type - The ({@link IEvent}) type to remove - * @param {Function} listener - The listener function to remove from the event target. - */ - removeEventListener: function () { } - - }, implementation); - - /** - * @interface IPlatform - * Allows abstracting platform dependencies away from the chart - * @borrows Chart.platform.acquireContext as acquireContext - * @borrows Chart.platform.releaseContext as releaseContext - * @borrows Chart.platform.addEventListener as addEventListener - * @borrows Chart.platform.removeEventListener as removeEventListener - */ - - /** - * @interface IEvent - * @prop {String} type - The event type name, possible values are: - * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout', - * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize' - * @prop {*} native - The original native event (null for emulated events, e.g. 'resize') - * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events) - * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events) - */ - - }, { "45": 45, "46": 46, "47": 47 }], 49: [function (require, module, exports) { - 'use strict'; - - module.exports = {}; - module.exports.filler = require(50); - module.exports.legend = require(51); - module.exports.title = require(52); - - }, { "50": 50, "51": 51, "52": 52 }], 50: [function (require, module, exports) { - /** - * Plugin based on discussion from the following Chart.js issues: - * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569 - * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897 - */ - - 'use strict'; - - var defaults = require(25); - var elements = require(40); - var helpers = require(45); - - defaults._set('global', { - plugins: { - filler: { - propagate: true - } - } - }); - - var mappers = { - dataset: function (source) { - var index = source.fill; - var chart = source.chart; - var meta = chart.getDatasetMeta(index); - var visible = meta && chart.isDatasetVisible(index); - var points = (visible && meta.dataset._children) || []; - var length = points.length || 0; - - return !length ? null : function (point, i) { - return (i < length && points[i]._view) || null; - }; - }, - - boundary: function (source) { - var boundary = source.boundary; - var x = boundary ? boundary.x : null; - var y = boundary ? boundary.y : null; - - return function (point) { - return { - x: x === null ? point.x : x, - y: y === null ? point.y : y, - }; - }; - } - }; - - // @todo if (fill[0] === '#') - function decodeFill(el, index, count) { - var model = el._model || {}; - var fill = model.fill; - var target; - - if (fill === undefined) { - fill = !!model.backgroundColor; - } - - if (fill === false || fill === null) { - return false; - } - - if (fill === true) { - return 'origin'; - } - - target = parseFloat(fill, 10); - if (isFinite(target) && Math.floor(target) === target) { - if (fill[0] === '-' || fill[0] === '+') { - target = index + target; - } - - if (target === index || target < 0 || target >= count) { - return false; - } - - return target; - } - - switch (fill) { - // compatibility - case 'bottom': - return 'start'; - case 'top': - return 'end'; - case 'zero': - return 'origin'; - // supported boundaries - case 'origin': - case 'start': - case 'end': - return fill; - // invalid fill values - default: - return false; - } - } - - function computeBoundary(source) { - var model = source.el._model || {}; - var scale = source.el._scale || {}; - var fill = source.fill; - var target = null; - var horizontal; - - if (isFinite(fill)) { - return null; - } - - // Backward compatibility: until v3, we still need to support boundary values set on - // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and - // controllers might still use it (e.g. the Smith chart). - - if (fill === 'start') { - target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom; - } else if (fill === 'end') { - target = model.scaleTop === undefined ? scale.top : model.scaleTop; - } else if (model.scaleZero !== undefined) { - target = model.scaleZero; - } else if (scale.getBasePosition) { - target = scale.getBasePosition(); - } else if (scale.getBasePixel) { - target = scale.getBasePixel(); - } - - if (target !== undefined && target !== null) { - if (target.x !== undefined && target.y !== undefined) { - return target; - } - - if (typeof target === 'number' && isFinite(target)) { - horizontal = scale.isHorizontal(); - return { - x: horizontal ? target : null, - y: horizontal ? null : target - }; - } - } - - return null; - } - - function resolveTarget(sources, index, propagate) { - var source = sources[index]; - var fill = source.fill; - var visited = [index]; - var target; - - if (!propagate) { - return fill; - } - - while (fill !== false && visited.indexOf(fill) === -1) { - if (!isFinite(fill)) { - return fill; - } - - target = sources[fill]; - if (!target) { - return false; - } - - if (target.visible) { - return fill; - } - - visited.push(fill); - fill = target.fill; - } - - return false; - } - - function createMapper(source) { - var fill = source.fill; - var type = 'dataset'; - - if (fill === false) { - return null; - } - - if (!isFinite(fill)) { - type = 'boundary'; - } - - return mappers[type](source); - } - - function isDrawable(point) { - return point && !point.skip; - } - - function drawArea(ctx, curve0, curve1, len0, len1) { - var i; - - if (!len0 || !len1) { - return; - } - - // building first area curve (normal) - ctx.moveTo(curve0[0].x, curve0[0].y); - for (i = 1; i < len0; ++i) { - helpers.canvas.lineTo(ctx, curve0[i - 1], curve0[i]); - } - - // joining the two area curves - ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y); - - // building opposite area curve (reverse) - for (i = len1 - 1; i > 0; --i) { - helpers.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true); - } - } - - function doFill(ctx, points, mapper, view, color, loop) { - var count = points.length; - var span = view.spanGaps; - var curve0 = []; - var curve1 = []; - var len0 = 0; - var len1 = 0; - var i, ilen, index, p0, p1, d0, d1; - - ctx.beginPath(); - - for (i = 0, ilen = (count + !!loop); i < ilen; ++i) { - index = i % count; - p0 = points[index]._view; - p1 = mapper(p0, index, view); - d0 = isDrawable(p0); - d1 = isDrawable(p1); - - if (d0 && d1) { - len0 = curve0.push(p0); - len1 = curve1.push(p1); - } else if (len0 && len1) { - if (!span) { - drawArea(ctx, curve0, curve1, len0, len1); - len0 = len1 = 0; - curve0 = []; - curve1 = []; - } else { - if (d0) { - curve0.push(p0); - } - if (d1) { - curve1.push(p1); - } - } - } - } - - drawArea(ctx, curve0, curve1, len0, len1); - - ctx.closePath(); - ctx.fillStyle = color; - ctx.fill(); - } - - module.exports = { - id: 'filler', - - afterDatasetsUpdate: function (chart, options) { - var count = (chart.data.datasets || []).length; - var propagate = options.propagate; - var sources = []; - var meta, i, el, source; - - for (i = 0; i < count; ++i) { - meta = chart.getDatasetMeta(i); - el = meta.dataset; - source = null; - - if (el && el._model && el instanceof elements.Line) { - source = { - visible: chart.isDatasetVisible(i), - fill: decodeFill(el, i, count), - chart: chart, - el: el - }; - } - - meta.$filler = source; - sources.push(source); - } - - for (i = 0; i < count; ++i) { - source = sources[i]; - if (!source) { - continue; - } - - source.fill = resolveTarget(sources, i, propagate); - source.boundary = computeBoundary(source); - source.mapper = createMapper(source); - } - }, - - beforeDatasetDraw: function (chart, args) { - var meta = args.meta.$filler; - if (!meta) { - return; - } - - var ctx = chart.ctx; - var el = meta.el; - var view = el._view; - var points = el._children || []; - var mapper = meta.mapper; - var color = view.backgroundColor || defaults.global.defaultColor; - - if (mapper && color && points.length) { - helpers.canvas.clipArea(ctx, chart.chartArea); - doFill(ctx, points, mapper, view, color, el._loop); - helpers.canvas.unclipArea(ctx); - } - } - }; - - }, { "25": 25, "40": 40, "45": 45 }], 51: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - var layouts = require(30); - - var noop = helpers.noop; - - defaults._set('global', { - legend: { - display: true, - position: 'top', - fullWidth: true, - reverse: false, - weight: 1000, - - // a callback that will handle - onClick: function (e, legendItem) { - var index = legendItem.datasetIndex; - var ci = this.chart; - var meta = ci.getDatasetMeta(index); - - // See controller.isDatasetVisible comment - meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null; - - // We hid a dataset ... rerender the chart - ci.update(); - }, - - onHover: null, - - labels: { - boxWidth: 40, - padding: 10, - // Generates labels shown in the legend - // Valid properties to return: - // text : text to display - // fillStyle : fill of coloured box - // strokeStyle: stroke of coloured box - // hidden : if this legend item refers to a hidden item - // lineCap : cap style for line - // lineDash - // lineDashOffset : - // lineJoin : - // lineWidth : - generateLabels: function (chart) { - var data = chart.data; - return helpers.isArray(data.datasets) ? data.datasets.map(function (dataset, i) { - return { - text: dataset.label, - fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]), - hidden: !chart.isDatasetVisible(i), - lineCap: dataset.borderCapStyle, - lineDash: dataset.borderDash, - lineDashOffset: dataset.borderDashOffset, - lineJoin: dataset.borderJoinStyle, - lineWidth: dataset.borderWidth, - strokeStyle: dataset.borderColor, - pointStyle: dataset.pointStyle, - - // Below is extra data used for toggling the datasets - datasetIndex: i - }; - }, this) : []; - } - } - }, - - legendCallback: function (chart) { - var text = []; - text.push('
    '); - for (var i = 0; i < chart.data.datasets.length; i++) { - text.push('
  • '); - if (chart.data.datasets[i].label) { - text.push(chart.data.datasets[i].label); - } - text.push('
  • '); - } - text.push('
'); - return text.join(''); - } - }); - - /** - * Helper function to get the box width based on the usePointStyle option - * @param labelopts {Object} the label options on the legend - * @param fontSize {Number} the label font size - * @return {Number} width of the color box area - */ - function getBoxWidth(labelOpts, fontSize) { - return labelOpts.usePointStyle ? - fontSize * Math.SQRT2 : - labelOpts.boxWidth; - } - - /** - * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required! - */ - var Legend = Element.extend({ - - initialize: function (config) { - helpers.extend(this, config); - - // Contains hit boxes for each dataset (in dataset order) - this.legendHitBoxes = []; - - // Are we in doughnut mode which has a different data type - this.doughnutMode = false; - }, - - // These methods are ordered by lifecycle. Utilities then follow. - // Any function defined here is inherited by all legend types. - // Any function can be extended by the legend type - - beforeUpdate: noop, - update: function (maxWidth, maxHeight, margins) { - var me = this; - - // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) - me.beforeUpdate(); - - // Absorb the master measurements - me.maxWidth = maxWidth; - me.maxHeight = maxHeight; - me.margins = margins; - - // Dimensions - me.beforeSetDimensions(); - me.setDimensions(); - me.afterSetDimensions(); - // Labels - me.beforeBuildLabels(); - me.buildLabels(); - me.afterBuildLabels(); - - // Fit - me.beforeFit(); - me.fit(); - me.afterFit(); - // - me.afterUpdate(); - - return me.minSize; - }, - afterUpdate: noop, - - // - - beforeSetDimensions: noop, - setDimensions: function () { - var me = this; - // Set the unconstrained dimension before label rotation - if (me.isHorizontal()) { - // Reset position before calculating rotation - me.width = me.maxWidth; - me.left = 0; - me.right = me.width; - } else { - me.height = me.maxHeight; - - // Reset position before calculating rotation - me.top = 0; - me.bottom = me.height; - } - - // Reset padding - me.paddingLeft = 0; - me.paddingTop = 0; - me.paddingRight = 0; - me.paddingBottom = 0; - - // Reset minSize - me.minSize = { - width: 0, - height: 0 - }; - }, - afterSetDimensions: noop, - - // - - beforeBuildLabels: noop, - buildLabels: function () { - var me = this; - var labelOpts = me.options.labels || {}; - var legendItems = helpers.callback(labelOpts.generateLabels, [me.chart], me) || []; - - if (labelOpts.filter) { - legendItems = legendItems.filter(function (item) { - return labelOpts.filter(item, me.chart.data); - }); - } - - if (me.options.reverse) { - legendItems.reverse(); - } - - me.legendItems = legendItems; - }, - afterBuildLabels: noop, - - // - - beforeFit: noop, - fit: function () { - var me = this; - var opts = me.options; - var labelOpts = opts.labels; - var display = opts.display; - - var ctx = me.ctx; - - var globalDefault = defaults.global; - var valueOrDefault = helpers.valueOrDefault; - var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize); - var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle); - var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily); - var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily); - - // Reset hit boxes - var hitboxes = me.legendHitBoxes = []; - - var minSize = me.minSize; - var isHorizontal = me.isHorizontal(); - - if (isHorizontal) { - minSize.width = me.maxWidth; // fill all the width - minSize.height = display ? 10 : 0; - } else { - minSize.width = display ? 10 : 0; - minSize.height = me.maxHeight; // fill all the height - } - - // Increase sizes here - if (display) { - ctx.font = labelFont; - - if (isHorizontal) { - // Labels - - // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one - var lineWidths = me.lineWidths = [0]; - var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0; - - ctx.textAlign = 'left'; - ctx.textBaseline = 'top'; - - helpers.each(me.legendItems, function (legendItem, i) { - var boxWidth = getBoxWidth(labelOpts, fontSize); - var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - - if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) { - totalHeight += fontSize + (labelOpts.padding); - lineWidths[lineWidths.length] = me.left; - } - - // Store the hitbox width and height here. Final position will be updated in `draw` - hitboxes[i] = { - left: 0, - top: 0, - width: width, - height: fontSize - }; - - lineWidths[lineWidths.length - 1] += width + labelOpts.padding; - }); - - minSize.height += totalHeight; - - } else { - var vPadding = labelOpts.padding; - var columnWidths = me.columnWidths = []; - var totalWidth = labelOpts.padding; - var currentColWidth = 0; - var currentColHeight = 0; - var itemHeight = fontSize + vPadding; - - helpers.each(me.legendItems, function (legendItem, i) { - var boxWidth = getBoxWidth(labelOpts, fontSize); - var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; - - // If too tall, go to new column - if (currentColHeight + itemHeight > minSize.height) { - totalWidth += currentColWidth + labelOpts.padding; - columnWidths.push(currentColWidth); // previous column width - - currentColWidth = 0; - currentColHeight = 0; - } - - // Get max width - currentColWidth = Math.max(currentColWidth, itemWidth); - currentColHeight += itemHeight; - - // Store the hitbox width and height here. Final position will be updated in `draw` - hitboxes[i] = { - left: 0, - top: 0, - width: itemWidth, - height: fontSize - }; - }); - - totalWidth += currentColWidth; - columnWidths.push(currentColWidth); - minSize.width += totalWidth; - } - } - - me.width = minSize.width; - me.height = minSize.height; - }, - afterFit: noop, - - // Shared Methods - isHorizontal: function () { - return this.options.position === 'top' || this.options.position === 'bottom'; - }, - - // Actually draw the legend on the canvas - draw: function () { - var me = this; - var opts = me.options; - var labelOpts = opts.labels; - var globalDefault = defaults.global; - var lineDefault = globalDefault.elements.line; - var legendWidth = me.width; - var lineWidths = me.lineWidths; - - if (opts.display) { - var ctx = me.ctx; - var valueOrDefault = helpers.valueOrDefault; - var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor); - var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize); - var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle); - var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily); - var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily); - var cursor; - - // Canvas setup - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - ctx.lineWidth = 0.5; - ctx.strokeStyle = fontColor; // for strikethrough effect - ctx.fillStyle = fontColor; // render in correct colour - ctx.font = labelFont; - - var boxWidth = getBoxWidth(labelOpts, fontSize); - var hitboxes = me.legendHitBoxes; - - // current position - var drawLegendBox = function (x, y, legendItem) { - if (isNaN(boxWidth) || boxWidth <= 0) { - return; - } - - // Set the ctx for the box - ctx.save(); - - ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor); - ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle); - ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset); - ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle); - ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth); - ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor); - var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0); - - if (ctx.setLineDash) { - // IE 9 and 10 do not support line dash - ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash)); - } - - if (opts.labels && opts.labels.usePointStyle) { - // Recalculate x and y for drawPoint() because its expecting - // x and y to be center of figure (instead of top left) - var radius = fontSize * Math.SQRT2 / 2; - var offSet = radius / Math.SQRT2; - var centerX = x + offSet; - var centerY = y + offSet; - - // Draw pointStyle as legend symbol - helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY); - } else { - // Draw box as legend symbol - if (!isLineWidthZero) { - ctx.strokeRect(x, y, boxWidth, fontSize); - } - ctx.fillRect(x, y, boxWidth, fontSize); - } - - ctx.restore(); - }; - var fillText = function (x, y, legendItem, textWidth) { - var halfFontSize = fontSize / 2; - var xLeft = boxWidth + halfFontSize + x; - var yMiddle = y + halfFontSize; - - ctx.fillText(legendItem.text, xLeft, yMiddle); - - if (legendItem.hidden) { - // Strikethrough the text if hidden - ctx.beginPath(); - ctx.lineWidth = 2; - ctx.moveTo(xLeft, yMiddle); - ctx.lineTo(xLeft + textWidth, yMiddle); - ctx.stroke(); - } - }; - - // Horizontal - var isHorizontal = me.isHorizontal(); - if (isHorizontal) { - cursor = { - x: me.left + ((legendWidth - lineWidths[0]) / 2), - y: me.top + labelOpts.padding, - line: 0 - }; - } else { - cursor = { - x: me.left + labelOpts.padding, - y: me.top + labelOpts.padding, - line: 0 - }; - } - - var itemHeight = fontSize + labelOpts.padding; - helpers.each(me.legendItems, function (legendItem, i) { - var textWidth = ctx.measureText(legendItem.text).width; - var width = boxWidth + (fontSize / 2) + textWidth; - var x = cursor.x; - var y = cursor.y; - - if (isHorizontal) { - if (x + width >= legendWidth) { - y = cursor.y += itemHeight; - cursor.line++; - x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2); - } - } else if (y + itemHeight > me.bottom) { - x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding; - y = cursor.y = me.top + labelOpts.padding; - cursor.line++; - } - - drawLegendBox(x, y, legendItem); - - hitboxes[i].left = x; - hitboxes[i].top = y; - - // Fill the actual label - fillText(x, y, legendItem, textWidth); - - if (isHorizontal) { - cursor.x += width + (labelOpts.padding); - } else { - cursor.y += itemHeight; - } - - }); - } - }, - - /** - * Handle an event - * @private - * @param {IEvent} event - The event to handle - * @return {Boolean} true if a change occured - */ - handleEvent: function (e) { - var me = this; - var opts = me.options; - var type = e.type === 'mouseup' ? 'click' : e.type; - var changed = false; - - if (type === 'mousemove') { - if (!opts.onHover) { - return; - } - } else if (type === 'click') { - if (!opts.onClick) { - return; - } - } else { - return; - } - - // Chart event already has relative position in it - var x = e.x; - var y = e.y; - - if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) { - // See if we are touching one of the dataset boxes - var lh = me.legendHitBoxes; - for (var i = 0; i < lh.length; ++i) { - var hitBox = lh[i]; - - if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) { - // Touching an element - if (type === 'click') { - // use e.native for backwards compatibility - opts.onClick.call(me, e.native, me.legendItems[i]); - changed = true; - break; - } else if (type === 'mousemove') { - // use e.native for backwards compatibility - opts.onHover.call(me, e.native, me.legendItems[i]); - changed = true; - break; - } - } - } - } - - return changed; - } - }); - - function createNewLegendAndAttach(chart, legendOpts) { - var legend = new Legend({ - ctx: chart.ctx, - options: legendOpts, - chart: chart - }); - - layouts.configure(chart, legend, legendOpts); - layouts.addBox(chart, legend); - chart.legend = legend; - } - - module.exports = { - id: 'legend', - - /** - * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making - * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of - * the plugin, which one will be re-exposed in the chart.js file. - * https://github.com/chartjs/Chart.js/pull/2640 - * @private - */ - _element: Legend, - - beforeInit: function (chart) { - var legendOpts = chart.options.legend; - - if (legendOpts) { - createNewLegendAndAttach(chart, legendOpts); - } - }, - - beforeUpdate: function (chart) { - var legendOpts = chart.options.legend; - var legend = chart.legend; - - if (legendOpts) { - helpers.mergeIf(legendOpts, defaults.global.legend); - - if (legend) { - layouts.configure(chart, legend, legendOpts); - legend.options = legendOpts; - } else { - createNewLegendAndAttach(chart, legendOpts); - } - } else if (legend) { - layouts.removeBox(chart, legend); - delete chart.legend; - } - }, - - afterEvent: function (chart, e) { - var legend = chart.legend; - if (legend) { - legend.handleEvent(e); - } - } - }; - - }, { "25": 25, "26": 26, "30": 30, "45": 45 }], 52: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var Element = require(26); - var helpers = require(45); - var layouts = require(30); - - var noop = helpers.noop; - - defaults._set('global', { - title: { - display: false, - fontStyle: 'bold', - fullWidth: true, - lineHeight: 1.2, - padding: 10, - position: 'top', - text: '', - weight: 2000 // by default greater than legend (1000) to be above - } - }); - - /** - * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required! - */ - var Title = Element.extend({ - initialize: function (config) { - var me = this; - helpers.extend(me, config); - - // Contains hit boxes for each dataset (in dataset order) - me.legendHitBoxes = []; - }, - - // These methods are ordered by lifecycle. Utilities then follow. - - beforeUpdate: noop, - update: function (maxWidth, maxHeight, margins) { - var me = this; - - // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) - me.beforeUpdate(); - - // Absorb the master measurements - me.maxWidth = maxWidth; - me.maxHeight = maxHeight; - me.margins = margins; - - // Dimensions - me.beforeSetDimensions(); - me.setDimensions(); - me.afterSetDimensions(); - // Labels - me.beforeBuildLabels(); - me.buildLabels(); - me.afterBuildLabels(); - - // Fit - me.beforeFit(); - me.fit(); - me.afterFit(); - // - me.afterUpdate(); - - return me.minSize; - - }, - afterUpdate: noop, - - // - - beforeSetDimensions: noop, - setDimensions: function () { - var me = this; - // Set the unconstrained dimension before label rotation - if (me.isHorizontal()) { - // Reset position before calculating rotation - me.width = me.maxWidth; - me.left = 0; - me.right = me.width; - } else { - me.height = me.maxHeight; - - // Reset position before calculating rotation - me.top = 0; - me.bottom = me.height; - } - - // Reset padding - me.paddingLeft = 0; - me.paddingTop = 0; - me.paddingRight = 0; - me.paddingBottom = 0; - - // Reset minSize - me.minSize = { - width: 0, - height: 0 - }; - }, - afterSetDimensions: noop, - - // - - beforeBuildLabels: noop, - buildLabels: noop, - afterBuildLabels: noop, - - // - - beforeFit: noop, - fit: function () { - var me = this; - var valueOrDefault = helpers.valueOrDefault; - var opts = me.options; - var display = opts.display; - var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize); - var minSize = me.minSize; - var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1; - var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize); - var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0; - - if (me.isHorizontal()) { - minSize.width = me.maxWidth; // fill all the width - minSize.height = textSize; - } else { - minSize.width = textSize; - minSize.height = me.maxHeight; // fill all the height - } - - me.width = minSize.width; - me.height = minSize.height; - - }, - afterFit: noop, - - // Shared Methods - isHorizontal: function () { - var pos = this.options.position; - return pos === 'top' || pos === 'bottom'; - }, - - // Actually draw the title block on the canvas - draw: function () { - var me = this; - var ctx = me.ctx; - var valueOrDefault = helpers.valueOrDefault; - var opts = me.options; - var globalDefaults = defaults.global; - - if (opts.display) { - var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize); - var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle); - var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily); - var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily); - var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize); - var offset = lineHeight / 2 + opts.padding; - var rotation = 0; - var top = me.top; - var left = me.left; - var bottom = me.bottom; - var right = me.right; - var maxWidth, titleX, titleY; - - ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour - ctx.font = titleFont; - - // Horizontal - if (me.isHorizontal()) { - titleX = left + ((right - left) / 2); // midpoint of the width - titleY = top + offset; - maxWidth = right - left; - } else { - titleX = opts.position === 'left' ? left + offset : right - offset; - titleY = top + ((bottom - top) / 2); - maxWidth = bottom - top; - rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5); - } - - ctx.save(); - ctx.translate(titleX, titleY); - ctx.rotate(rotation); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - - var text = opts.text; - if (helpers.isArray(text)) { - var y = 0; - for (var i = 0; i < text.length; ++i) { - ctx.fillText(text[i], 0, y, maxWidth); - y += lineHeight; - } - } else { - ctx.fillText(text, 0, 0, maxWidth); - } - - ctx.restore(); - } - } - }); - - function createNewTitleBlockAndAttach(chart, titleOpts) { - var title = new Title({ - ctx: chart.ctx, - options: titleOpts, - chart: chart - }); - - layouts.configure(chart, title, titleOpts); - layouts.addBox(chart, title); - chart.titleBlock = title; - } - - module.exports = { - id: 'title', - - /** - * Backward compatibility: since 2.1.5, the title is registered as a plugin, making - * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of - * the plugin, which one will be re-exposed in the chart.js file. - * https://github.com/chartjs/Chart.js/pull/2640 - * @private - */ - _element: Title, - - beforeInit: function (chart) { - var titleOpts = chart.options.title; - - if (titleOpts) { - createNewTitleBlockAndAttach(chart, titleOpts); - } - }, - - beforeUpdate: function (chart) { - var titleOpts = chart.options.title; - var titleBlock = chart.titleBlock; - - if (titleOpts) { - helpers.mergeIf(titleOpts, defaults.global.title); - - if (titleBlock) { - layouts.configure(chart, titleBlock, titleOpts); - titleBlock.options = titleOpts; - } else { - createNewTitleBlockAndAttach(chart, titleOpts); - } - } else if (titleBlock) { - layouts.removeBox(chart, titleBlock); - delete chart.titleBlock; - } - } - }; - - }, { "25": 25, "26": 26, "30": 30, "45": 45 }], 53: [function (require, module, exports) { - 'use strict'; - - module.exports = function (Chart) { - - // Default config for a category scale - var defaultConfig = { - position: 'bottom' - }; - - var DatasetScale = Chart.Scale.extend({ - /** - * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those - * else fall back to data.labels - * @private - */ - getLabels: function () { - var data = this.chart.data; - return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels; - }, - - determineDataLimits: function () { - var me = this; - var labels = me.getLabels(); - me.minIndex = 0; - me.maxIndex = labels.length - 1; - var findIndex; - - if (me.options.ticks.min !== undefined) { - // user specified min value - findIndex = labels.indexOf(me.options.ticks.min); - me.minIndex = findIndex !== -1 ? findIndex : me.minIndex; - } - - if (me.options.ticks.max !== undefined) { - // user specified max value - findIndex = labels.indexOf(me.options.ticks.max); - me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex; - } - - me.min = labels[me.minIndex]; - me.max = labels[me.maxIndex]; - }, - - buildTicks: function () { - var me = this; - var labels = me.getLabels(); - // If we are viewing some subset of labels, slice the original array - me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1); - }, - - getLabelForIndex: function (index, datasetIndex) { - var me = this; - var data = me.chart.data; - var isHorizontal = me.isHorizontal(); - - if (data.yLabels && !isHorizontal) { - return me.getRightValue(data.datasets[datasetIndex].data[index]); - } - return me.ticks[index - me.minIndex]; - }, - - // Used to get data value locations. Value can either be an index or a numerical value - getPixelForValue: function (value, index) { - var me = this; - var offset = me.options.offset; - // 1 is added because we need the length but we have the indexes - var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1); - - // If value is a data object, then index is the index in the data array, - // not the index of the scale. We need to change that. - var valueCategory; - if (value !== undefined && value !== null) { - valueCategory = me.isHorizontal() ? value.x : value.y; - } - if (valueCategory !== undefined || (value !== undefined && isNaN(index))) { - var labels = me.getLabels(); - value = valueCategory || value; - var idx = labels.indexOf(value); - index = idx !== -1 ? idx : index; - } - - if (me.isHorizontal()) { - var valueWidth = me.width / offsetAmt; - var widthOffset = (valueWidth * (index - me.minIndex)); - - if (offset) { - widthOffset += (valueWidth / 2); - } - - return me.left + Math.round(widthOffset); - } - var valueHeight = me.height / offsetAmt; - var heightOffset = (valueHeight * (index - me.minIndex)); - - if (offset) { - heightOffset += (valueHeight / 2); - } - - return me.top + Math.round(heightOffset); - }, - getPixelForTick: function (index) { - return this.getPixelForValue(this.ticks[index], index + this.minIndex, null); - }, - getValueForPixel: function (pixel) { - var me = this; - var offset = me.options.offset; - var value; - var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1); - var horz = me.isHorizontal(); - var valueDimension = (horz ? me.width : me.height) / offsetAmt; - - pixel -= horz ? me.left : me.top; - - if (offset) { - pixel -= (valueDimension / 2); - } - - if (pixel <= 0) { - value = 0; - } else { - value = Math.round(pixel / valueDimension); - } - - return value + me.minIndex; - }, - getBasePixel: function () { - return this.bottom; - } - }); - - Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig); - - }; - - }, {}], 54: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var helpers = require(45); - var Ticks = require(34); - - module.exports = function (Chart) { - - var defaultConfig = { - position: 'left', - ticks: { - callback: Ticks.formatters.linear - } - }; - - var LinearScale = Chart.LinearScaleBase.extend({ - - determineDataLimits: function () { - var me = this; - var opts = me.options; - var chart = me.chart; - var data = chart.data; - var datasets = data.datasets; - var isHorizontal = me.isHorizontal(); - var DEFAULT_MIN = 0; - var DEFAULT_MAX = 1; - - function IDMatches(meta) { - return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id; - } - - // First Calculate the range - me.min = null; - me.max = null; - - var hasStacks = opts.stacked; - if (hasStacks === undefined) { - helpers.each(datasets, function (dataset, datasetIndex) { - if (hasStacks) { - return; - } - - var meta = chart.getDatasetMeta(datasetIndex); - if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) && - meta.stack !== undefined) { - hasStacks = true; - } - }); - } - - if (opts.stacked || hasStacks) { - var valuesPerStack = {}; - - helpers.each(datasets, function (dataset, datasetIndex) { - var meta = chart.getDatasetMeta(datasetIndex); - var key = [ - meta.type, - // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined - ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''), - meta.stack - ].join('.'); - - if (valuesPerStack[key] === undefined) { - valuesPerStack[key] = { - positiveValues: [], - negativeValues: [] - }; - } - - // Store these per type - var positiveValues = valuesPerStack[key].positiveValues; - var negativeValues = valuesPerStack[key].negativeValues; - - if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { - helpers.each(dataset.data, function (rawValue, index) { - var value = +me.getRightValue(rawValue); - if (isNaN(value) || meta.data[index].hidden) { - return; - } - - positiveValues[index] = positiveValues[index] || 0; - negativeValues[index] = negativeValues[index] || 0; - - if (opts.relativePoints) { - positiveValues[index] = 100; - } else if (value < 0) { - negativeValues[index] += value; - } else { - positiveValues[index] += value; - } - }); - } - }); - - helpers.each(valuesPerStack, function (valuesForType) { - var values = valuesForType.positiveValues.concat(valuesForType.negativeValues); - var minVal = helpers.min(values); - var maxVal = helpers.max(values); - me.min = me.min === null ? minVal : Math.min(me.min, minVal); - me.max = me.max === null ? maxVal : Math.max(me.max, maxVal); - }); - - } else { - helpers.each(datasets, function (dataset, datasetIndex) { - var meta = chart.getDatasetMeta(datasetIndex); - if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { - helpers.each(dataset.data, function (rawValue, index) { - var value = +me.getRightValue(rawValue); - if (isNaN(value) || meta.data[index].hidden) { - return; - } - - if (me.min === null) { - me.min = value; - } else if (value < me.min) { - me.min = value; - } - - if (me.max === null) { - me.max = value; - } else if (value > me.max) { - me.max = value; - } - }); - } - }); - } - - me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN; - me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX; - - // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero - this.handleTickRangeOptions(); - }, - getTickLimit: function () { - var maxTicks; - var me = this; - var tickOpts = me.options.ticks; - - if (me.isHorizontal()) { - maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50)); - } else { - // The factor of 2 used to scale the font size has been experimentally determined. - var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize); - maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize))); - } - - return maxTicks; - }, - // Called after the ticks are built. We need - handleDirectionalChanges: function () { - if (!this.isHorizontal()) { - // We are in a vertical orientation. The top value is the highest. So reverse the array - this.ticks.reverse(); - } - }, - getLabelForIndex: function (index, datasetIndex) { - return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); - }, - // Utils - getPixelForValue: function (value) { - // This must be called after fit has been run so that - // this.left, this.top, this.right, and this.bottom have been defined - var me = this; - var start = me.start; - - var rightValue = +me.getRightValue(value); - var pixel; - var range = me.end - start; - - if (me.isHorizontal()) { - pixel = me.left + (me.width / range * (rightValue - start)); - } else { - pixel = me.bottom - (me.height / range * (rightValue - start)); - } - return pixel; - }, - getValueForPixel: function (pixel) { - var me = this; - var isHorizontal = me.isHorizontal(); - var innerDimension = isHorizontal ? me.width : me.height; - var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension; - return me.start + ((me.end - me.start) * offset); - }, - getPixelForTick: function (index) { - return this.getPixelForValue(this.ticksAsNumbers[index]); - } - }); - Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig); - - }; - - }, { "25": 25, "34": 34, "45": 45 }], 55: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - - /** - * Generate a set of linear ticks - * @param generationOptions the options used to generate the ticks - * @param dataRange the range of the data - * @returns {Array} array of tick values - */ - function generateTicks(generationOptions, dataRange) { - var ticks = []; - // To get a "nice" value for the tick spacing, we will use the appropriately named - // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks - // for details. - - var spacing; - if (generationOptions.stepSize && generationOptions.stepSize > 0) { - spacing = generationOptions.stepSize; - } else { - var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false); - spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true); - } - var niceMin = Math.floor(dataRange.min / spacing) * spacing; - var niceMax = Math.ceil(dataRange.max / spacing) * spacing; - - // If min, max and stepSize is set and they make an evenly spaced scale use it. - if (generationOptions.min && generationOptions.max && generationOptions.stepSize) { - // If very close to our whole number, use it. - if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) { - niceMin = generationOptions.min; - niceMax = generationOptions.max; - } - } - - var numSpaces = (niceMax - niceMin) / spacing; - // If very close to our rounded value, use it. - if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { - numSpaces = Math.round(numSpaces); - } else { - numSpaces = Math.ceil(numSpaces); - } - - var precision = 1; - if (spacing < 1) { - precision = Math.pow(10, spacing.toString().length - 2); - niceMin = Math.round(niceMin * precision) / precision; - niceMax = Math.round(niceMax * precision) / precision; - } - ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin); - for (var j = 1; j < numSpaces; ++j) { - ticks.push(Math.round((niceMin + j * spacing) * precision) / precision); - } - ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax); - - return ticks; - } - - - module.exports = function (Chart) { - - var noop = helpers.noop; - - Chart.LinearScaleBase = Chart.Scale.extend({ - getRightValue: function (value) { - if (typeof value === 'string') { - return +value; - } - return Chart.Scale.prototype.getRightValue.call(this, value); - }, - - handleTickRangeOptions: function () { - var me = this; - var opts = me.options; - var tickOpts = opts.ticks; - - // If we are forcing it to begin at 0, but 0 will already be rendered on the chart, - // do nothing since that would make the chart weird. If the user really wants a weird chart - // axis, they can manually override it - if (tickOpts.beginAtZero) { - var minSign = helpers.sign(me.min); - var maxSign = helpers.sign(me.max); - - if (minSign < 0 && maxSign < 0) { - // move the top up to 0 - me.max = 0; - } else if (minSign > 0 && maxSign > 0) { - // move the bottom down to 0 - me.min = 0; - } - } - - var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined; - var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined; - - if (tickOpts.min !== undefined) { - me.min = tickOpts.min; - } else if (tickOpts.suggestedMin !== undefined) { - if (me.min === null) { - me.min = tickOpts.suggestedMin; - } else { - me.min = Math.min(me.min, tickOpts.suggestedMin); - } - } - - if (tickOpts.max !== undefined) { - me.max = tickOpts.max; - } else if (tickOpts.suggestedMax !== undefined) { - if (me.max === null) { - me.max = tickOpts.suggestedMax; - } else { - me.max = Math.max(me.max, tickOpts.suggestedMax); - } - } - - if (setMin !== setMax) { - // We set the min or the max but not both. - // So ensure that our range is good - // Inverted or 0 length range can happen when - // ticks.min is set, and no datasets are visible - if (me.min >= me.max) { - if (setMin) { - me.max = me.min + 1; - } else { - me.min = me.max - 1; - } - } - } - - if (me.min === me.max) { - me.max++; - - if (!tickOpts.beginAtZero) { - me.min--; - } - } - }, - getTickLimit: noop, - handleDirectionalChanges: noop, - - buildTicks: function () { - var me = this; - var opts = me.options; - var tickOpts = opts.ticks; - - // Figure out what the max number of ticks we can support it is based on the size of - // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 - // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on - // the graph. Make sure we always have at least 2 ticks - var maxTicks = me.getTickLimit(); - maxTicks = Math.max(2, maxTicks); - - var numericGeneratorOptions = { - maxTicks: maxTicks, - min: tickOpts.min, - max: tickOpts.max, - stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize) - }; - var ticks = me.ticks = generateTicks(numericGeneratorOptions, me); - - me.handleDirectionalChanges(); - - // At this point, we need to update our max and min given the tick values since we have expanded the - // range of the scale - me.max = helpers.max(ticks); - me.min = helpers.min(ticks); - - if (tickOpts.reverse) { - ticks.reverse(); - - me.start = me.max; - me.end = me.min; - } else { - me.start = me.min; - me.end = me.max; - } - }, - convertTicksToLabels: function () { - var me = this; - me.ticksAsNumbers = me.ticks.slice(); - me.zeroLineIndex = me.ticks.indexOf(0); - - Chart.Scale.prototype.convertTicksToLabels.call(me); - } - }); - }; - - }, { "45": 45 }], 56: [function (require, module, exports) { - 'use strict'; - - var helpers = require(45); - var Ticks = require(34); - - /** - * Generate a set of logarithmic ticks - * @param generationOptions the options used to generate the ticks - * @param dataRange the range of the data - * @returns {Array} array of tick values - */ - function generateTicks(generationOptions, dataRange) { - var ticks = []; - var valueOrDefault = helpers.valueOrDefault; - - // Figure out what the max number of ticks we can support it is based on the size of - // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 - // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on - // the graph - var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min)))); - - var endExp = Math.floor(helpers.log10(dataRange.max)); - var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); - var exp, significand; - - if (tickVal === 0) { - exp = Math.floor(helpers.log10(dataRange.minNotZero)); - significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp)); - - ticks.push(tickVal); - tickVal = significand * Math.pow(10, exp); - } else { - exp = Math.floor(helpers.log10(tickVal)); - significand = Math.floor(tickVal / Math.pow(10, exp)); - } - var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; - - do { - ticks.push(tickVal); - - ++significand; - if (significand === 10) { - significand = 1; - ++exp; - precision = exp >= 0 ? 1 : precision; - } - - tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; - } while (exp < endExp || (exp === endExp && significand < endSignificand)); - - var lastTick = valueOrDefault(generationOptions.max, tickVal); - ticks.push(lastTick); - - return ticks; - } - - - module.exports = function (Chart) { - - var defaultConfig = { - position: 'left', - - // label settings - ticks: { - callback: Ticks.formatters.logarithmic - } - }; - - var LogarithmicScale = Chart.Scale.extend({ - determineDataLimits: function () { - var me = this; - var opts = me.options; - var chart = me.chart; - var data = chart.data; - var datasets = data.datasets; - var isHorizontal = me.isHorizontal(); - function IDMatches(meta) { - return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id; - } - - // Calculate Range - me.min = null; - me.max = null; - me.minNotZero = null; - - var hasStacks = opts.stacked; - if (hasStacks === undefined) { - helpers.each(datasets, function (dataset, datasetIndex) { - if (hasStacks) { - return; - } - - var meta = chart.getDatasetMeta(datasetIndex); - if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) && - meta.stack !== undefined) { - hasStacks = true; - } - }); - } - - if (opts.stacked || hasStacks) { - var valuesPerStack = {}; - - helpers.each(datasets, function (dataset, datasetIndex) { - var meta = chart.getDatasetMeta(datasetIndex); - var key = [ - meta.type, - // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined - ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''), - meta.stack - ].join('.'); - - if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { - if (valuesPerStack[key] === undefined) { - valuesPerStack[key] = []; - } - - helpers.each(dataset.data, function (rawValue, index) { - var values = valuesPerStack[key]; - var value = +me.getRightValue(rawValue); - // invalid, hidden and negative values are ignored - if (isNaN(value) || meta.data[index].hidden || value < 0) { - return; - } - values[index] = values[index] || 0; - values[index] += value; - }); - } - }); - - helpers.each(valuesPerStack, function (valuesForType) { - if (valuesForType.length > 0) { - var minVal = helpers.min(valuesForType); - var maxVal = helpers.max(valuesForType); - me.min = me.min === null ? minVal : Math.min(me.min, minVal); - me.max = me.max === null ? maxVal : Math.max(me.max, maxVal); - } - }); - - } else { - helpers.each(datasets, function (dataset, datasetIndex) { - var meta = chart.getDatasetMeta(datasetIndex); - if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { - helpers.each(dataset.data, function (rawValue, index) { - var value = +me.getRightValue(rawValue); - // invalid, hidden and negative values are ignored - if (isNaN(value) || meta.data[index].hidden || value < 0) { - return; - } - - if (me.min === null) { - me.min = value; - } else if (value < me.min) { - me.min = value; - } - - if (me.max === null) { - me.max = value; - } else if (value > me.max) { - me.max = value; - } - - if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) { - me.minNotZero = value; - } - }); - } - }); - } - - // Common base implementation to handle ticks.min, ticks.max - this.handleTickRangeOptions(); - }, - handleTickRangeOptions: function () { - var me = this; - var opts = me.options; - var tickOpts = opts.ticks; - var valueOrDefault = helpers.valueOrDefault; - var DEFAULT_MIN = 1; - var DEFAULT_MAX = 10; - - me.min = valueOrDefault(tickOpts.min, me.min); - me.max = valueOrDefault(tickOpts.max, me.max); - - if (me.min === me.max) { - if (me.min !== 0 && me.min !== null) { - me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1); - me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1); - } else { - me.min = DEFAULT_MIN; - me.max = DEFAULT_MAX; - } - } - if (me.min === null) { - me.min = Math.pow(10, Math.floor(helpers.log10(me.max)) - 1); - } - if (me.max === null) { - me.max = me.min !== 0 - ? Math.pow(10, Math.floor(helpers.log10(me.min)) + 1) - : DEFAULT_MAX; - } - if (me.minNotZero === null) { - if (me.min > 0) { - me.minNotZero = me.min; - } else if (me.max < 1) { - me.minNotZero = Math.pow(10, Math.floor(helpers.log10(me.max))); - } else { - me.minNotZero = DEFAULT_MIN; - } - } - }, - buildTicks: function () { - var me = this; - var opts = me.options; - var tickOpts = opts.ticks; - var reverse = !me.isHorizontal(); - - var generationOptions = { - min: tickOpts.min, - max: tickOpts.max - }; - var ticks = me.ticks = generateTicks(generationOptions, me); - - // At this point, we need to update our max and min given the tick values since we have expanded the - // range of the scale - me.max = helpers.max(ticks); - me.min = helpers.min(ticks); - - if (tickOpts.reverse) { - reverse = !reverse; - me.start = me.max; - me.end = me.min; - } else { - me.start = me.min; - me.end = me.max; - } - if (reverse) { - ticks.reverse(); - } - }, - convertTicksToLabels: function () { - this.tickValues = this.ticks.slice(); - - Chart.Scale.prototype.convertTicksToLabels.call(this); - }, - // Get the correct tooltip label - getLabelForIndex: function (index, datasetIndex) { - return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); - }, - getPixelForTick: function (index) { - return this.getPixelForValue(this.tickValues[index]); - }, - /** - * Returns the value of the first tick. - * @param {Number} value - The minimum not zero value. - * @return {Number} The first tick value. - * @private - */ - _getFirstTickValue: function (value) { - var exp = Math.floor(helpers.log10(value)); - var significand = Math.floor(value / Math.pow(10, exp)); - - return significand * Math.pow(10, exp); - }, - getPixelForValue: function (value) { - var me = this; - var reverse = me.options.ticks.reverse; - var log10 = helpers.log10; - var firstTickValue = me._getFirstTickValue(me.minNotZero); - var offset = 0; - var innerDimension, pixel, start, end, sign; - - value = +me.getRightValue(value); - if (reverse) { - start = me.end; - end = me.start; - sign = -1; - } else { - start = me.start; - end = me.end; - sign = 1; - } - if (me.isHorizontal()) { - innerDimension = me.width; - pixel = reverse ? me.right : me.left; - } else { - innerDimension = me.height; - sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0) - pixel = reverse ? me.top : me.bottom; - } - if (value !== start) { - if (start === 0) { // include zero tick - offset = helpers.getValueOrDefault( - me.options.ticks.fontSize, - Chart.defaults.global.defaultFontSize - ); - innerDimension -= offset; - start = firstTickValue; - } - if (value !== 0) { - offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start)); - } - pixel += sign * offset; - } - return pixel; - }, - getValueForPixel: function (pixel) { - var me = this; - var reverse = me.options.ticks.reverse; - var log10 = helpers.log10; - var firstTickValue = me._getFirstTickValue(me.minNotZero); - var innerDimension, start, end, value; - - if (reverse) { - start = me.end; - end = me.start; - } else { - start = me.start; - end = me.end; - } - if (me.isHorizontal()) { - innerDimension = me.width; - value = reverse ? me.right - pixel : pixel - me.left; - } else { - innerDimension = me.height; - value = reverse ? pixel - me.top : me.bottom - pixel; - } - if (value !== start) { - if (start === 0) { // include zero tick - var offset = helpers.getValueOrDefault( - me.options.ticks.fontSize, - Chart.defaults.global.defaultFontSize - ); - value -= offset; - innerDimension -= offset; - start = firstTickValue; - } - value *= log10(end) - log10(start); - value /= innerDimension; - value = Math.pow(10, log10(start) + value); - } - return value; - } - }); - Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig); - - }; - - }, { "34": 34, "45": 45 }], 57: [function (require, module, exports) { - 'use strict'; - - var defaults = require(25); - var helpers = require(45); - var Ticks = require(34); - - module.exports = function (Chart) { - - var globalDefaults = defaults.global; - - var defaultConfig = { - display: true, - - // Boolean - Whether to animate scaling the chart from the centre - animate: true, - position: 'chartArea', - - angleLines: { - display: true, - color: 'rgba(0, 0, 0, 0.1)', - lineWidth: 1 - }, - - gridLines: { - circular: false - }, - - // label settings - ticks: { - // Boolean - Show a backdrop to the scale label - showLabelBackdrop: true, - - // String - The colour of the label backdrop - backdropColor: 'rgba(255,255,255,0.75)', - - // Number - The backdrop padding above & below the label in pixels - backdropPaddingY: 2, - - // Number - The backdrop padding to the side of the label in pixels - backdropPaddingX: 2, - - callback: Ticks.formatters.linear - }, - - pointLabels: { - // Boolean - if true, show point labels - display: true, - - // Number - Point label font size in pixels - fontSize: 10, - - // Function - Used to convert point labels - callback: function (label) { - return label; - } - } - }; - - function getValueCount(scale) { - var opts = scale.options; - return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0; - } - - function getPointLabelFontOptions(scale) { - var pointLabelOptions = scale.options.pointLabels; - var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize); - var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle); - var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily); - var font = helpers.fontString(fontSize, fontStyle, fontFamily); - - return { - size: fontSize, - style: fontStyle, - family: fontFamily, - font: font - }; - } - - function measureLabelSize(ctx, fontSize, label) { - if (helpers.isArray(label)) { - return { - w: helpers.longestText(ctx, ctx.font, label), - h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize) - }; - } - - return { - w: ctx.measureText(label).width, - h: fontSize - }; - } - - function determineLimits(angle, pos, size, min, max) { - if (angle === min || angle === max) { - return { - start: pos - (size / 2), - end: pos + (size / 2) - }; - } else if (angle < min || angle > max) { - return { - start: pos - size - 5, - end: pos - }; - } - - return { - start: pos, - end: pos + size + 5 - }; - } - - /** - * Helper function to fit a radial linear scale with point labels - */ - function fitWithPointLabels(scale) { - /* - * Right, this is really confusing and there is a lot of maths going on here - * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9 - * - * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif - * - * Solution: - * - * We assume the radius of the polygon is half the size of the canvas at first - * at each index we check if the text overlaps. - * - * Where it does, we store that angle and that index. - * - * After finding the largest index and angle we calculate how much we need to remove - * from the shape radius to move the point inwards by that x. - * - * We average the left and right distances to get the maximum shape radius that can fit in the box - * along with labels. - * - * Once we have that, we can find the centre point for the chart, by taking the x text protrusion - * on each side, removing that from the size, halving it and adding the left x protrusion width. - * - * This will mean we have a shape fitted to the canvas, as large as it can be with the labels - * and position it in the most space efficient manner - * - * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif - */ - - var plFont = getPointLabelFontOptions(scale); - - // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width. - // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points - var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2); - var furthestLimits = { - r: scale.width, - l: 0, - t: scale.height, - b: 0 - }; - var furthestAngles = {}; - var i, textSize, pointPosition; - - scale.ctx.font = plFont.font; - scale._pointLabelSizes = []; - - var valueCount = getValueCount(scale); - for (i = 0; i < valueCount; i++) { - pointPosition = scale.getPointPosition(i, largestPossibleRadius); - textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || ''); - scale._pointLabelSizes[i] = textSize; - - // Add quarter circle to make degree 0 mean top of circle - var angleRadians = scale.getIndexAngle(i); - var angle = helpers.toDegrees(angleRadians) % 360; - var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); - var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); - - if (hLimits.start < furthestLimits.l) { - furthestLimits.l = hLimits.start; - furthestAngles.l = angleRadians; - } - - if (hLimits.end > furthestLimits.r) { - furthestLimits.r = hLimits.end; - furthestAngles.r = angleRadians; - } - - if (vLimits.start < furthestLimits.t) { - furthestLimits.t = vLimits.start; - furthestAngles.t = angleRadians; - } - - if (vLimits.end > furthestLimits.b) { - furthestLimits.b = vLimits.end; - furthestAngles.b = angleRadians; - } - } - - scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles); - } - - /** - * Helper function to fit a radial linear scale with no point labels - */ - function fit(scale) { - var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2); - scale.drawingArea = Math.round(largestPossibleRadius); - scale.setCenterPoint(0, 0, 0, 0); - } - - function getTextAlignForAngle(angle) { - if (angle === 0 || angle === 180) { - return 'center'; - } else if (angle < 180) { - return 'left'; - } - - return 'right'; - } - - function fillText(ctx, text, position, fontSize) { - if (helpers.isArray(text)) { - var y = position.y; - var spacing = 1.5 * fontSize; - - for (var i = 0; i < text.length; ++i) { - ctx.fillText(text[i], position.x, y); - y += spacing; - } - } else { - ctx.fillText(text, position.x, position.y); - } - } - - function adjustPointPositionForLabelHeight(angle, textSize, position) { - if (angle === 90 || angle === 270) { - position.y -= (textSize.h / 2); - } else if (angle > 270 || angle < 90) { - position.y -= textSize.h; - } - } - - function drawPointLabels(scale) { - var ctx = scale.ctx; - var opts = scale.options; - var angleLineOpts = opts.angleLines; - var pointLabelOpts = opts.pointLabels; - - ctx.lineWidth = angleLineOpts.lineWidth; - ctx.strokeStyle = angleLineOpts.color; - - var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); - - // Point Label Font - var plFont = getPointLabelFontOptions(scale); - - ctx.textBaseline = 'top'; - - for (var i = getValueCount(scale) - 1; i >= 0; i--) { - if (angleLineOpts.display) { - var outerPosition = scale.getPointPosition(i, outerDistance); - ctx.beginPath(); - ctx.moveTo(scale.xCenter, scale.yCenter); - ctx.lineTo(outerPosition.x, outerPosition.y); - ctx.stroke(); - ctx.closePath(); - } - - if (pointLabelOpts.display) { - // Extra 3px out for some label spacing - var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5); - - // Keep this in loop since we may support array properties here - var pointLabelFontColor = helpers.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, globalDefaults.defaultFontColor); - ctx.font = plFont.font; - ctx.fillStyle = pointLabelFontColor; - - var angleRadians = scale.getIndexAngle(i); - var angle = helpers.toDegrees(angleRadians); - ctx.textAlign = getTextAlignForAngle(angle); - adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition); - fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size); - } - } - } - - function drawRadiusLine(scale, gridLineOpts, radius, index) { - var ctx = scale.ctx; - ctx.strokeStyle = helpers.valueAtIndexOrDefault(gridLineOpts.color, index - 1); - ctx.lineWidth = helpers.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1); - - if (scale.options.gridLines.circular) { - // Draw circular arcs between the points - ctx.beginPath(); - ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2); - ctx.closePath(); - ctx.stroke(); - } else { - // Draw straight lines connecting each index - var valueCount = getValueCount(scale); - - if (valueCount === 0) { - return; - } - - ctx.beginPath(); - var pointPosition = scale.getPointPosition(0, radius); - ctx.moveTo(pointPosition.x, pointPosition.y); - - for (var i = 1; i < valueCount; i++) { - pointPosition = scale.getPointPosition(i, radius); - ctx.lineTo(pointPosition.x, pointPosition.y); - } - - ctx.closePath(); - ctx.stroke(); - } - } - - function numberOrZero(param) { - return helpers.isNumber(param) ? param : 0; - } - - var LinearRadialScale = Chart.LinearScaleBase.extend({ - setDimensions: function () { - var me = this; - var opts = me.options; - var tickOpts = opts.ticks; - // Set the unconstrained dimension before label rotation - me.width = me.maxWidth; - me.height = me.maxHeight; - me.xCenter = Math.round(me.width / 2); - me.yCenter = Math.round(me.height / 2); - - var minSize = helpers.min([me.height, me.width]); - var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize); - me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2); - }, - determineDataLimits: function () { - var me = this; - var chart = me.chart; - var min = Number.POSITIVE_INFINITY; - var max = Number.NEGATIVE_INFINITY; - - helpers.each(chart.data.datasets, function (dataset, datasetIndex) { - if (chart.isDatasetVisible(datasetIndex)) { - var meta = chart.getDatasetMeta(datasetIndex); - - helpers.each(dataset.data, function (rawValue, index) { - var value = +me.getRightValue(rawValue); - if (isNaN(value) || meta.data[index].hidden) { - return; - } - - min = Math.min(value, min); - max = Math.max(value, max); - }); - } - }); - - me.min = (min === Number.POSITIVE_INFINITY ? 0 : min); - me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max); - - // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero - me.handleTickRangeOptions(); - }, - getTickLimit: function () { - var tickOpts = this.options.ticks; - var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize); - return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize))); - }, - convertTicksToLabels: function () { - var me = this; - - Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me); - - // Point labels - me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me); - }, - getLabelForIndex: function (index, datasetIndex) { - return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); - }, - fit: function () { - if (this.options.pointLabels.display) { - fitWithPointLabels(this); - } else { - fit(this); - } - }, - /** - * Set radius reductions and determine new radius and center point - * @private - */ - setReductions: function (largestPossibleRadius, furthestLimits, furthestAngles) { - var me = this; - var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l); - var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r); - var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t); - var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b); - - radiusReductionLeft = numberOrZero(radiusReductionLeft); - radiusReductionRight = numberOrZero(radiusReductionRight); - radiusReductionTop = numberOrZero(radiusReductionTop); - radiusReductionBottom = numberOrZero(radiusReductionBottom); - - me.drawingArea = Math.min( - Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2), - Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2)); - me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom); - }, - setCenterPoint: function (leftMovement, rightMovement, topMovement, bottomMovement) { - var me = this; - var maxRight = me.width - rightMovement - me.drawingArea; - var maxLeft = leftMovement + me.drawingArea; - var maxTop = topMovement + me.drawingArea; - var maxBottom = me.height - bottomMovement - me.drawingArea; - - me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left); - me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top); - }, - - getIndexAngle: function (index) { - var angleMultiplier = (Math.PI * 2) / getValueCount(this); - var startAngle = this.chart.options && this.chart.options.startAngle ? - this.chart.options.startAngle : - 0; - - var startAngleRadians = startAngle * Math.PI * 2 / 360; - - // Start from the top instead of right, so remove a quarter of the circle - return index * angleMultiplier + startAngleRadians; - }, - getDistanceFromCenterForValue: function (value) { - var me = this; - - if (value === null) { - return 0; // null always in center - } - - // Take into account half font size + the yPadding of the top value - var scalingFactor = me.drawingArea / (me.max - me.min); - if (me.options.ticks.reverse) { - return (me.max - value) * scalingFactor; - } - return (value - me.min) * scalingFactor; - }, - getPointPosition: function (index, distanceFromCenter) { - var me = this; - var thisAngle = me.getIndexAngle(index) - (Math.PI / 2); - return { - x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter, - y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter - }; - }, - getPointPositionForValue: function (index, value) { - return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); - }, - - getBasePosition: function () { - var me = this; - var min = me.min; - var max = me.max; - - return me.getPointPositionForValue(0, - me.beginAtZero ? 0 : - min < 0 && max < 0 ? max : - min > 0 && max > 0 ? min : - 0); - }, - - draw: function () { - var me = this; - var opts = me.options; - var gridLineOpts = opts.gridLines; - var tickOpts = opts.ticks; - var valueOrDefault = helpers.valueOrDefault; - - if (opts.display) { - var ctx = me.ctx; - var startAngle = this.getIndexAngle(0); - - // Tick Font - var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize); - var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle); - var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily); - var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); - - helpers.each(me.ticks, function (label, index) { - // Don't draw a centre value (if it is minimum) - if (index > 0 || tickOpts.reverse) { - var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]); - - // Draw circular lines around the scale - if (gridLineOpts.display && index !== 0) { - drawRadiusLine(me, gridLineOpts, yCenterOffset, index); - } - - if (tickOpts.display) { - var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor); - ctx.font = tickLabelFont; - - ctx.save(); - ctx.translate(me.xCenter, me.yCenter); - ctx.rotate(startAngle); - - if (tickOpts.showLabelBackdrop) { - var labelWidth = ctx.measureText(label).width; - ctx.fillStyle = tickOpts.backdropColor; - ctx.fillRect( - -labelWidth / 2 - tickOpts.backdropPaddingX, - -yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY, - labelWidth + tickOpts.backdropPaddingX * 2, - tickFontSize + tickOpts.backdropPaddingY * 2 - ); - } - - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = tickFontColor; - ctx.fillText(label, 0, -yCenterOffset); - ctx.restore(); - } - } - }); - - if (opts.angleLines.display || opts.pointLabels.display) { - drawPointLabels(me); - } - } - } - }); - Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig); - - }; - - }, { "25": 25, "34": 34, "45": 45 }], 58: [function (require, module, exports) { - /* global window: false */ - 'use strict'; - - var moment = require(6); - moment = typeof moment === 'function' ? moment : window.moment; - - var defaults = require(25); - var helpers = require(45); - - // Integer constants are from the ES6 spec. - var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991; - var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; - - var INTERVALS = { - millisecond: { - common: true, - size: 1, - steps: [1, 2, 5, 10, 20, 50, 100, 250, 500] - }, - second: { - common: true, - size: 1000, - steps: [1, 2, 5, 10, 30] - }, - minute: { - common: true, - size: 60000, - steps: [1, 2, 5, 10, 30] - }, - hour: { - common: true, - size: 3600000, - steps: [1, 2, 3, 6, 12] - }, - day: { - common: true, - size: 86400000, - steps: [1, 2, 5] - }, - week: { - common: false, - size: 604800000, - steps: [1, 2, 3, 4] - }, - month: { - common: true, - size: 2.628e9, - steps: [1, 2, 3] - }, - quarter: { - common: false, - size: 7.884e9, - steps: [1, 2, 3, 4] - }, - year: { - common: true, - size: 3.154e10 - } - }; - - var UNITS = Object.keys(INTERVALS); - - function sorter(a, b) { - return a - b; - } - - function arrayUnique(items) { - var hash = {}; - var out = []; - var i, ilen, item; - - for (i = 0, ilen = items.length; i < ilen; ++i) { - item = items[i]; - if (!hash[item]) { - hash[item] = true; - out.push(item); - } - } - - return out; - } - - /** - * Returns an array of {time, pos} objects used to interpolate a specific `time` or position - * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is - * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other - * extremity (left + width or top + height). Note that it would be more optimized to directly - * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need - * to create the lookup table. The table ALWAYS contains at least two items: min and max. - * - * @param {Number[]} timestamps - timestamps sorted from lowest to highest. - * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min - * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}. - * If 'series', timestamps will be positioned at the same distance from each other. In this - * case, only timestamps that break the time linearity are registered, meaning that in the - * best case, all timestamps are linear, the table contains only min and max. - */ - function buildLookupTable(timestamps, min, max, distribution) { - if (distribution === 'linear' || !timestamps.length) { - return [ - { time: min, pos: 0 }, - { time: max, pos: 1 } - ]; - } - - var table = []; - var items = [min]; - var i, ilen, prev, curr, next; - - for (i = 0, ilen = timestamps.length; i < ilen; ++i) { - curr = timestamps[i]; - if (curr > min && curr < max) { - items.push(curr); - } - } - - items.push(max); - - for (i = 0, ilen = items.length; i < ilen; ++i) { - next = items[i + 1]; - prev = items[i - 1]; - curr = items[i]; - - // only add points that breaks the scale linearity - if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) { - table.push({ time: curr, pos: i / (ilen - 1) }); - } - } - - return table; - } - - // @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/ - function lookup(table, key, value) { - var lo = 0; - var hi = table.length - 1; - var mid, i0, i1; - - while (lo >= 0 && lo <= hi) { - mid = (lo + hi) >> 1; - i0 = table[mid - 1] || null; - i1 = table[mid]; - - if (!i0) { - // given value is outside table (before first item) - return { lo: null, hi: i1 }; - } else if (i1[key] < value) { - lo = mid + 1; - } else if (i0[key] > value) { - hi = mid - 1; - } else { - return { lo: i0, hi: i1 }; - } - } - - // given value is outside table (after last item) - return { lo: i1, hi: null }; - } - - /** - * Linearly interpolates the given source `value` using the table items `skey` values and - * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos') - * returns the position for a timestamp equal to 42. If value is out of bounds, values at - * index [0, 1] or [n - 1, n] are used for the interpolation. - */ - function interpolate(table, skey, sval, tkey) { - var range = lookup(table, skey, sval); - - // Note: the lookup table ALWAYS contains at least 2 items (min and max) - var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo; - var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi; - - var span = next[skey] - prev[skey]; - var ratio = span ? (sval - prev[skey]) / span : 0; - var offset = (next[tkey] - prev[tkey]) * ratio; - - return prev[tkey] + offset; - } - - /** - * Convert the given value to a moment object using the given time options. - * @see http://momentjs.com/docs/#/parsing/ - */ - function momentify(value, options) { - var parser = options.parser; - var format = options.parser || options.format; - - if (typeof parser === 'function') { - return parser(value); - } - - if (typeof value === 'string' && typeof format === 'string') { - return moment(value, format); - } - - if (!(value instanceof moment)) { - value = moment(value); - } - - if (value.isValid()) { - return value; - } - - // Labels are in an incompatible moment format and no `parser` has been provided. - // The user might still use the deprecated `format` option to convert his inputs. - if (typeof format === 'function') { - return format(value); - } - - return value; - } - - function parse(input, scale) { - if (helpers.isNullOrUndef(input)) { - return null; - } - - var options = scale.options.time; - var value = momentify(scale.getRightValue(input), options); - if (!value.isValid()) { - return null; - } - - if (options.round) { - value.startOf(options.round); - } - - return value.valueOf(); - } - - /** - * Returns the number of unit to skip to be able to display up to `capacity` number of ticks - * in `unit` for the given `min` / `max` range and respecting the interval steps constraints. - */ - function determineStepSize(min, max, unit, capacity) { - var range = max - min; - var interval = INTERVALS[unit]; - var milliseconds = interval.size; - var steps = interval.steps; - var i, ilen, factor; - - if (!steps) { - return Math.ceil(range / (capacity * milliseconds)); - } - - for (i = 0, ilen = steps.length; i < ilen; ++i) { - factor = steps[i]; - if (Math.ceil(range / (milliseconds * factor)) <= capacity) { - break; - } - } - - return factor; - } - - /** - * Figures out what unit results in an appropriate number of auto-generated ticks - */ - function determineUnitForAutoTicks(minUnit, min, max, capacity) { - var ilen = UNITS.length; - var i, interval, factor; - - for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { - interval = INTERVALS[UNITS[i]]; - factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER; - - if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { - return UNITS[i]; - } - } - - return UNITS[ilen - 1]; - } - - /** - * Figures out what unit to format a set of ticks with - */ - function determineUnitForFormatting(ticks, minUnit, min, max) { - var duration = moment.duration(moment(max).diff(moment(min))); - var ilen = UNITS.length; - var i, unit; - - for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) { - unit = UNITS[i]; - if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) { - return unit; - } - } - - return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; - } - - function determineMajorUnit(unit) { - for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { - if (INTERVALS[UNITS[i]].common) { - return UNITS[i]; - } - } - } - - /** - * Generates a maximum of `capacity` timestamps between min and max, rounded to the - * `minor` unit, aligned on the `major` unit and using the given scale time `options`. - * Important: this method can return ticks outside the min and max range, it's the - * responsibility of the calling code to clamp values if needed. - */ - function generate(min, max, capacity, options) { - var timeOpts = options.time; - var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity); - var major = determineMajorUnit(minor); - var stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize); - var weekday = minor === 'week' ? timeOpts.isoWeekday : false; - var majorTicksEnabled = options.ticks.major.enabled; - var interval = INTERVALS[minor]; - var first = moment(min); - var last = moment(max); - var ticks = []; - var time; - - if (!stepSize) { - stepSize = determineStepSize(min, max, minor, capacity); - } - - // For 'week' unit, handle the first day of week option - if (weekday) { - first = first.isoWeekday(weekday); - last = last.isoWeekday(weekday); - } - - // Align first/last ticks on unit - first = first.startOf(weekday ? 'day' : minor); - last = last.startOf(weekday ? 'day' : minor); - - // Make sure that the last tick include max - if (last < max) { - last.add(1, minor); - } - - time = moment(first); - - if (majorTicksEnabled && major && !weekday && !timeOpts.round) { - // Align the first tick on the previous `minor` unit aligned on the `major` unit: - // we first aligned time on the previous `major` unit then add the number of full - // stepSize there is between first and the previous major time. - time.startOf(major); - time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor); - } - - for (; time < last; time.add(stepSize, minor)) { - ticks.push(+time); - } - - ticks.push(+time); - - return ticks; - } - - /** - * Returns the right and left offsets from edges in the form of {left, right}. - * Offsets are added when the `offset` option is true. - */ - function computeOffsets(table, ticks, min, max, options) { - var left = 0; - var right = 0; - var upper, lower; - - if (options.offset && ticks.length) { - if (!options.time.min) { - upper = ticks.length > 1 ? ticks[1] : max; - lower = ticks[0]; - left = ( - interpolate(table, 'time', upper, 'pos') - - interpolate(table, 'time', lower, 'pos') - ) / 2; - } - if (!options.time.max) { - upper = ticks[ticks.length - 1]; - lower = ticks.length > 1 ? ticks[ticks.length - 2] : min; - right = ( - interpolate(table, 'time', upper, 'pos') - - interpolate(table, 'time', lower, 'pos') - ) / 2; - } - } - - return { left: left, right: right }; - } - - function ticksFromTimestamps(values, majorUnit) { - var ticks = []; - var i, ilen, value, major; - - for (i = 0, ilen = values.length; i < ilen; ++i) { - value = values[i]; - major = majorUnit ? value === +moment(value).startOf(majorUnit) : false; - - ticks.push({ - value: value, - major: major - }); - } - - return ticks; - } - - function determineLabelFormat(data, timeOpts) { - var i, momentDate, hasTime; - var ilen = data.length; - - // find the label with the most parts (milliseconds, minutes, etc.) - // format all labels with the same level of detail as the most specific label - for (i = 0; i < ilen; i++) { - momentDate = momentify(data[i], timeOpts); - if (momentDate.millisecond() !== 0) { - return 'MMM D, YYYY h:mm:ss.SSS a'; - } - if (momentDate.second() !== 0 || momentDate.minute() !== 0 || momentDate.hour() !== 0) { - hasTime = true; - } - } - if (hasTime) { - return 'MMM D, YYYY h:mm:ss a'; - } - return 'MMM D, YYYY'; - } - - module.exports = function (Chart) { - - var defaultConfig = { - position: 'bottom', - - /** - * Data distribution along the scale: - * - 'linear': data are spread according to their time (distances can vary), - * - 'series': data are spread at the same distance from each other. - * @see https://github.com/chartjs/Chart.js/pull/4507 - * @since 2.7.0 - */ - distribution: 'linear', - - /** - * Scale boundary strategy (bypassed by min/max time options) - * - `data`: make sure data are fully visible, ticks outside are removed - * - `ticks`: make sure ticks are fully visible, data outside are truncated - * @see https://github.com/chartjs/Chart.js/pull/4556 - * @since 2.7.0 - */ - bounds: 'data', - - time: { - parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment - format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/ - unit: false, // false == automatic or override with week, month, year, etc. - round: false, // none, or override with week, month, year, etc. - displayFormat: false, // DEPRECATED - isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/ - minUnit: 'millisecond', - - // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/ - displayFormats: { - millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM, - second: 'h:mm:ss a', // 11:20:01 AM - minute: 'h:mm a', // 11:20 AM - hour: 'hA', // 5PM - day: 'MMM D', // Sep 4 - week: 'll', // Week 46, or maybe "[W]WW - YYYY" ? - month: 'MMM YYYY', // Sept 2015 - quarter: '[Q]Q - YYYY', // Q3 - year: 'YYYY' // 2015 - }, - }, - ticks: { - autoSkip: false, - - /** - * Ticks generation input values: - * - 'auto': generates "optimal" ticks based on scale size and time options. - * - 'data': generates ticks from data (including labels from data {t|x|y} objects). - * - 'labels': generates ticks from user given `data.labels` values ONLY. - * @see https://github.com/chartjs/Chart.js/pull/4507 - * @since 2.7.0 - */ - source: 'auto', - - major: { - enabled: false - } - } - }; - - var TimeScale = Chart.Scale.extend({ - initialize: function () { - if (!moment) { - throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com'); - } - - this.mergeTicksOptions(); - - Chart.Scale.prototype.initialize.call(this); - }, - - update: function () { - var me = this; - var options = me.options; - - // DEPRECATIONS: output a message only one time per update - if (options.time && options.time.format) { - console.warn('options.time.format is deprecated and replaced by options.time.parser.'); - } - - return Chart.Scale.prototype.update.apply(me, arguments); - }, - - /** - * Allows data to be referenced via 't' attribute - */ - getRightValue: function (rawValue) { - if (rawValue && rawValue.t !== undefined) { - rawValue = rawValue.t; - } - return Chart.Scale.prototype.getRightValue.call(this, rawValue); - }, - - determineDataLimits: function () { - var me = this; - var chart = me.chart; - var timeOpts = me.options.time; - var unit = timeOpts.unit || 'day'; - var min = MAX_INTEGER; - var max = MIN_INTEGER; - var timestamps = []; - var datasets = []; - var labels = []; - var i, j, ilen, jlen, data, timestamp; - - // Convert labels to timestamps - for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) { - labels.push(parse(chart.data.labels[i], me)); - } - - // Convert data to timestamps - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - if (chart.isDatasetVisible(i)) { - data = chart.data.datasets[i].data; - - // Let's consider that all data have the same format. - if (helpers.isObject(data[0])) { - datasets[i] = []; - - for (j = 0, jlen = data.length; j < jlen; ++j) { - timestamp = parse(data[j], me); - timestamps.push(timestamp); - datasets[i][j] = timestamp; - } - } else { - timestamps.push.apply(timestamps, labels); - datasets[i] = labels.slice(0); - } - } else { - datasets[i] = []; - } - } - - if (labels.length) { - // Sort labels **after** data have been converted - labels = arrayUnique(labels).sort(sorter); - min = Math.min(min, labels[0]); - max = Math.max(max, labels[labels.length - 1]); - } - - if (timestamps.length) { - timestamps = arrayUnique(timestamps).sort(sorter); - min = Math.min(min, timestamps[0]); - max = Math.max(max, timestamps[timestamps.length - 1]); - } - - min = parse(timeOpts.min, me) || min; - max = parse(timeOpts.max, me) || max; - - // In case there is no valid min/max, set limits based on unit time option - min = min === MAX_INTEGER ? +moment().startOf(unit) : min; - max = max === MIN_INTEGER ? +moment().endOf(unit) + 1 : max; - - // Make sure that max is strictly higher than min (required by the lookup table) - me.min = Math.min(min, max); - me.max = Math.max(min + 1, max); - - // PRIVATE - me._horizontal = me.isHorizontal(); - me._table = []; - me._timestamps = { - data: timestamps, - datasets: datasets, - labels: labels - }; - }, - - buildTicks: function () { - var me = this; - var min = me.min; - var max = me.max; - var options = me.options; - var timeOpts = options.time; - var timestamps = []; - var ticks = []; - var i, ilen, timestamp; - - switch (options.ticks.source) { - case 'data': - timestamps = me._timestamps.data; - break; - case 'labels': - timestamps = me._timestamps.labels; - break; - case 'auto': - default: - timestamps = generate(min, max, me.getLabelCapacity(min), options); - } - - if (options.bounds === 'ticks' && timestamps.length) { - min = timestamps[0]; - max = timestamps[timestamps.length - 1]; - } - - // Enforce limits with user min/max options - min = parse(timeOpts.min, me) || min; - max = parse(timeOpts.max, me) || max; - - // Remove ticks outside the min/max range - for (i = 0, ilen = timestamps.length; i < ilen; ++i) { - timestamp = timestamps[i]; - if (timestamp >= min && timestamp <= max) { - ticks.push(timestamp); - } - } - - me.min = min; - me.max = max; - - // PRIVATE - me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max); - me._majorUnit = determineMajorUnit(me._unit); - me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution); - me._offsets = computeOffsets(me._table, ticks, min, max, options); - me._labelFormat = determineLabelFormat(me._timestamps.data, timeOpts); - - return ticksFromTimestamps(ticks, me._majorUnit); - }, - - getLabelForIndex: function (index, datasetIndex) { - var me = this; - var data = me.chart.data; - var timeOpts = me.options.time; - var label = data.labels && index < data.labels.length ? data.labels[index] : ''; - var value = data.datasets[datasetIndex].data[index]; - - if (helpers.isObject(value)) { - label = me.getRightValue(value); - } - if (timeOpts.tooltipFormat) { - return momentify(label, timeOpts).format(timeOpts.tooltipFormat); - } - if (typeof label === 'string') { - return label; - } - - return momentify(label, timeOpts).format(me._labelFormat); - }, - - /** - * Function to format an individual tick mark - * @private - */ - tickFormatFunction: function (tick, index, ticks, formatOverride) { - var me = this; - var options = me.options; - var time = tick.valueOf(); - var formats = options.time.displayFormats; - var minorFormat = formats[me._unit]; - var majorUnit = me._majorUnit; - var majorFormat = formats[majorUnit]; - var majorTime = tick.clone().startOf(majorUnit).valueOf(); - var majorTickOpts = options.ticks.major; - var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime; - var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat); - var tickOpts = major ? majorTickOpts : options.ticks.minor; - var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback); - - return formatter ? formatter(label, index, ticks) : label; - }, - - convertTicksToLabels: function (ticks) { - var labels = []; - var i, ilen; - - for (i = 0, ilen = ticks.length; i < ilen; ++i) { - labels.push(this.tickFormatFunction(moment(ticks[i].value), i, ticks)); - } - - return labels; - }, - - /** - * @private - */ - getPixelForOffset: function (time) { - var me = this; - var size = me._horizontal ? me.width : me.height; - var start = me._horizontal ? me.left : me.top; - var pos = interpolate(me._table, 'time', time, 'pos'); - - return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right); - }, - - getPixelForValue: function (value, index, datasetIndex) { - var me = this; - var time = null; - - if (index !== undefined && datasetIndex !== undefined) { - time = me._timestamps.datasets[datasetIndex][index]; - } - - if (time === null) { - time = parse(value, me); - } - - if (time !== null) { - return me.getPixelForOffset(time); - } - }, - - getPixelForTick: function (index) { - var ticks = this.getTicks(); - return index >= 0 && index < ticks.length ? - this.getPixelForOffset(ticks[index].value) : - null; - }, - - getValueForPixel: function (pixel) { - var me = this; - var size = me._horizontal ? me.width : me.height; - var start = me._horizontal ? me.left : me.top; - var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right; - var time = interpolate(me._table, 'pos', pos, 'time'); - - return moment(time); - }, - - /** - * Crude approximation of what the label width might be - * @private - */ - getLabelWidth: function (label) { - var me = this; - var ticksOpts = me.options.ticks; - var tickLabelWidth = me.ctx.measureText(label).width; - var angle = helpers.toRadians(ticksOpts.maxRotation); - var cosRotation = Math.cos(angle); - var sinRotation = Math.sin(angle); - var tickFontSize = helpers.valueOrDefault(ticksOpts.fontSize, defaults.global.defaultFontSize); - - return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation); - }, - - /** - * @private - */ - getLabelCapacity: function (exampleTime) { - var me = this; - - var formatOverride = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation - - var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride); - var tickLabelWidth = me.getLabelWidth(exampleLabel); - var innerWidth = me.isHorizontal() ? me.width : me.height; - - var capacity = Math.floor(innerWidth / tickLabelWidth); - return capacity > 0 ? capacity : 1; - } - }); - - Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig); - }; - - }, { "25": 25, "45": 45, "6": 6 }] - }, {}, [7])(7) -}); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Chart=e()}(this,(function(){"use strict";var t=Object.freeze({__proto__:null,get Colors(){return Ko},get Decimation(){return Jo},get Filler(){return pa},get Legend(){return _a},get SubTitle(){return wa},get Title(){return va},get Tooltip(){return Va}});function e(){}const i=(()=>{let t=0;return()=>t++})();function s(t){return null==t}function n(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.slice(0,7)&&"Array]"===e.slice(-6)}function o(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}function a(t){return("number"==typeof t||t instanceof Number)&&isFinite(+t)}function r(t,e){return a(t)?t:e}function l(t,e){return void 0===t?e:t}const h=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:+t/e,c=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function d(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function u(t,e,i,s){let a,r,l;if(n(t))if(r=t.length,s)for(a=r-1;a>=0;a--)e.call(i,t[a],a);else for(a=0;at,x:t=>t.x,y:t=>t.y};function v(t){const e=t.split("."),i=[];let s="";for(const t of e)s+=t,s.endsWith("\\")?s=s.slice(0,-1)+".":(i.push(s),s="");return i}function M(t,e){const i=y[e]||(y[e]=function(t){const e=v(t);return t=>{for(const i of e){if(""===i)break;t=t&&t[i]}return t}}(e));return i(t)}function w(t){return t.charAt(0).toUpperCase()+t.slice(1)}const k=t=>void 0!==t,S=t=>"function"==typeof t,P=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function D(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const C=Math.PI,O=2*C,A=O+C,T=Number.POSITIVE_INFINITY,L=C/180,E=C/2,R=C/4,I=2*C/3,z=Math.log10,F=Math.sign;function V(t,e,i){return Math.abs(t-e)t-e)).pop(),e}function N(t){return!isNaN(parseFloat(t))&&isFinite(t)}function H(t,e){const i=Math.round(t);return i-e<=t&&i+e>=t}function j(t,e,i){let s,n,o;for(s=0,n=t.length;sl&&h=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function et(t,e,i){i=i||(i=>t[i]1;)s=o+n>>1,i(s)?o=s:n=s;return{lo:o,hi:n}}const it=(t,e,i,s)=>et(t,i,s?s=>{const n=t[s][e];return nt[s][e]et(t,i,(s=>t[s][e]>=i));function nt(t,e,i){let s=0,n=t.length;for(;ss&&t[n-1]>i;)n--;return s>0||n{const i="_onData"+w(e),s=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value(...e){const n=s.apply(this,e);return t._chartjs.listeners.forEach((t=>{"function"==typeof t[i]&&t[i](...e)})),n}})})))}function rt(t,e){const i=t._chartjs;if(!i)return;const s=i.listeners,n=s.indexOf(e);-1!==n&&s.splice(n,1),s.length>0||(ot.forEach((e=>{delete t[e]})),delete t._chartjs)}function lt(t){const e=new Set(t);return e.size===t.length?t:Array.from(e)}const ht="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function ct(t,e){let i=[],s=!1;return function(...n){i=n,s||(s=!0,ht.call(window,(()=>{s=!1,t.apply(e,i)})))}}function dt(t,e){let i;return function(...s){return e?(clearTimeout(i),i=setTimeout(t,e,s)):t.apply(this,s),e}}const ut=t=>"start"===t?"left":"end"===t?"right":"center",ft=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,gt=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;function pt(t,e,i){const s=e.length;let n=0,o=s;if(t._sorted){const{iScale:a,_parsed:r}=t,l=a.axis,{min:h,max:c,minDefined:d,maxDefined:u}=a.getUserBounds();d&&(n=J(Math.min(it(r,l,h).lo,i?s:it(e,l,a.getPixelForValue(h)).lo),0,s-1)),o=u?J(Math.max(it(r,a.axis,c,!0).hi+1,i?0:it(e,l,a.getPixelForValue(c),!0).hi+1),n,s)-n:s-n}return{start:n,count:o}}function mt(t){const{xScale:e,yScale:i,_scaleRanges:s}=t,n={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=n,!0;const o=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,n),o}class bt{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,e,i,s){const n=e.listeners[s],o=e.duration;n.forEach((s=>s({chart:t,initial:e.initial,numSteps:o,currentStep:Math.min(i-e.start,o)})))}_refresh(){this._request||(this._running=!0,this._request=ht.call(window,(()=>{this._update(),this._request=null,this._running&&this._refresh()})))}_update(t=Date.now()){let e=0;this._charts.forEach(((i,s)=>{if(!i.running||!i.items.length)return;const n=i.items;let o,a=n.length-1,r=!1;for(;a>=0;--a)o=n[a],o._active?(o._total>i.duration&&(i.duration=o._total),o.tick(t),r=!0):(n[a]=n[n.length-1],n.pop());r&&(s.draw(),this._notify(s,i,t,"progress")),n.length||(i.running=!1,this._notify(s,i,t,"complete"),i.initial=!1),e+=n.length})),this._lastDate=t,0===e&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return this._getAnims(t).items.length>0}start(t){const e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(((t,e)=>Math.max(t,e._duration)),0),this._refresh())}running(t){if(!this._running)return!1;const e=this._charts.get(t);return!!(e&&e.running&&e.items.length)}stop(t){const e=this._charts.get(t);if(!e||!e.items.length)return;const i=e.items;let s=i.length-1;for(;s>=0;--s)i[s].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}var xt=new bt; +/*! + * @kurkle/color v0.3.2 + * https://github.com/kurkle/color#readme + * (c) 2023 Jukka Kurkela + * Released under the MIT License + */function _t(t){return t+.5|0}const yt=(t,e,i)=>Math.max(Math.min(t,i),e);function vt(t){return yt(_t(2.55*t),0,255)}function Mt(t){return yt(_t(255*t),0,255)}function wt(t){return yt(_t(t/2.55)/100,0,1)}function kt(t){return yt(_t(100*t),0,100)}const St={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Pt=[..."0123456789ABCDEF"],Dt=t=>Pt[15&t],Ct=t=>Pt[(240&t)>>4]+Pt[15&t],Ot=t=>(240&t)>>4==(15&t);function At(t){var e=(t=>Ot(t.r)&&Ot(t.g)&&Ot(t.b)&&Ot(t.a))(t)?Dt:Ct;return t?"#"+e(t.r)+e(t.g)+e(t.b)+((t,e)=>t<255?e(t):"")(t.a,e):void 0}const Tt=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Lt(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function Et(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function Rt(t,e,i){const s=Lt(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function It(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=function(t,e,i,s,n){return t===n?(e-i)/s+(e>16&255,o>>8&255,255&o]}return t}(),Ht.transparent=[0,0,0,0]);const e=Ht[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}const $t=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const Yt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Ut=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4);function Xt(t,e,i){if(t){let s=It(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=Ft(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function qt(t,e){return t?Object.assign(e||{},t):t}function Kt(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=Mt(t[3]))):(e=qt(t,{r:0,g:0,b:0,a:1})).a=Mt(e.a),e}function Gt(t){return"r"===t.charAt(0)?function(t){const e=$t.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=e[8]?vt(t):yt(255*t,0,255)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?vt(i):yt(i,0,255)),s=255&(e[4]?vt(s):yt(s,0,255)),n=255&(e[6]?vt(n):yt(n,0,255)),{r:i,g:s,b:n,a:o}}}(t):Bt(t)}class Zt{constructor(t){if(t instanceof Zt)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=Kt(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*St[s[1]],g:255&17*St[s[2]],b:255&17*St[s[3]],a:5===o?17*St[s[4]]:255}:7!==o&&9!==o||(n={r:St[s[1]]<<4|St[s[2]],g:St[s[3]]<<4|St[s[4]],b:St[s[5]]<<4|St[s[6]],a:9===o?St[s[7]]<<4|St[s[8]]:255})),i=n||jt(t)||Gt(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=qt(this._rgb);return t&&(t.a=wt(t.a)),t}set rgb(t){this._rgb=Kt(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${wt(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):void 0;var t}hexString(){return this._valid?At(this._rgb):void 0}hslString(){return this._valid?function(t){if(!t)return;const e=It(t),i=e[0],s=kt(e[1]),n=kt(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${wt(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):void 0}mix(t,e){if(t){const i=this.rgb,s=t.rgb;let n;const o=e===n?.5:e,a=2*o-1,r=i.a-s.a,l=((a*r==-1?a:(a+r)/(1+a*r))+1)/2;n=1-l,i.r=255&l*i.r+n*s.r+.5,i.g=255&l*i.g+n*s.g+.5,i.b=255&l*i.b+n*s.b+.5,i.a=o*i.a+(1-o)*s.a,this.rgb=i}return this}interpolate(t,e){return t&&(this._rgb=function(t,e,i){const s=Ut(wt(t.r)),n=Ut(wt(t.g)),o=Ut(wt(t.b));return{r:Mt(Yt(s+i*(Ut(wt(e.r))-s))),g:Mt(Yt(n+i*(Ut(wt(e.g))-n))),b:Mt(Yt(o+i*(Ut(wt(e.b))-o))),a:t.a+i*(e.a-t.a)}}(this._rgb,t._rgb,e)),this}clone(){return new Zt(this.rgb)}alpha(t){return this._rgb.a=Mt(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=_t(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return Xt(this._rgb,2,t),this}darken(t){return Xt(this._rgb,2,-t),this}saturate(t){return Xt(this._rgb,1,t),this}desaturate(t){return Xt(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=It(t);i[0]=Vt(i[0]+e),i=Ft(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function Jt(t){if(t&&"object"==typeof t){const e=t.toString();return"[object CanvasPattern]"===e||"[object CanvasGradient]"===e}return!1}function Qt(t){return Jt(t)?t:new Zt(t)}function te(t){return Jt(t)?t:new Zt(t).saturate(.5).darken(.1).hexString()}const ee=["x","y","borderWidth","radius","tension"],ie=["color","borderColor","backgroundColor"];const se=new Map;function ne(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=se.get(i);return s||(s=new Intl.NumberFormat(t,e),se.set(i,s)),s}(e,i).format(t)}const oe={values:t=>n(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=z(Math.abs(o)),r=isNaN(a)?1:Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),ne(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=i[e].significand||t/Math.pow(10,Math.floor(z(t)));return[1,2,3,5,10,15].includes(s)||e>.8*i.length?oe.numeric.call(this,t,e,i):""}};var ae={formatters:oe};const re=Object.create(null),le=Object.create(null);function he(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;et.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>te(e.backgroundColor),this.hoverBorderColor=(t,e)=>te(e.borderColor),this.hoverColor=(t,e)=>te(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(e)}set(t,e){return ce(this,t,e)}get(t){return he(this,t)}describe(t,e){return ce(le,t,e)}override(t,e){return ce(re,t,e)}route(t,e,i,s){const n=he(this,t),a=he(this,i),r="_"+e;Object.defineProperties(n,{[r]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[r],e=a[s];return o(t)?Object.assign({},e,t):l(t,e)},set(t){this[r]=t}}})}apply(t){t.forEach((t=>t(this)))}}var ue=new de({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(t){t.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),t.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),t.set("animations",{colors:{type:"color",properties:ie},numbers:{type:"number",properties:ee}}),t.describe("animations",{_fallback:"animation"}),t.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}})},function(t){t.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(t){t.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,e)=>e.lineWidth,tickColor:(t,e)=>e.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:ae.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),t.route("scale.ticks","color","","color"),t.route("scale.grid","color","","borderColor"),t.route("scale.border","color","","borderColor"),t.route("scale.title","color","","color"),t.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t&&"dash"!==t}),t.describe("scales",{_fallback:"scale"}),t.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t})}]);function fe(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ge(t){let e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e}function pe(t,e,i){let s;return"string"==typeof t?(s=parseInt(t,10),-1!==t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}const me=t=>t.ownerDocument.defaultView.getComputedStyle(t,null);function be(t,e){return me(t).getPropertyValue(e)}const xe=["top","right","bottom","left"];function _e(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=xe[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}const ye=(t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot);function ve(t,e){if("native"in t)return t;const{canvas:i,currentDevicePixelRatio:s}=e,n=me(i),o="border-box"===n.boxSizing,a=_e(n,"padding"),r=_e(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.touches,s=i&&i.length?i[0]:t,{offsetX:n,offsetY:o}=s;let a,r,l=!1;if(ye(n,o,t.target))a=n,r=o;else{const t=e.getBoundingClientRect();a=s.clientX-t.left,r=s.clientY-t.top,l=!0}return{x:a,y:r,box:l}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const Me=t=>Math.round(10*t)/10;function we(t,e,i,s){const n=me(t),o=_e(n,"margin"),a=pe(n.maxWidth,t,"clientWidth")||T,r=pe(n.maxHeight,t,"clientHeight")||T,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=ge(t);if(o){const t=o.getBoundingClientRect(),a=me(o),r=_e(a,"border","width"),l=_e(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=pe(a.maxWidth,o,"clientWidth"),n=pe(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||T,maxHeight:n||T}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=_e(n,"border","width"),e=_e(n,"padding");h-=e.width+t.width,c-=e.height+t.height}h=Math.max(0,h-o.width),c=Math.max(0,s?h/s:c-o.height),h=Me(Math.min(h,a,l.maxWidth)),c=Me(Math.min(c,r,l.maxHeight)),h&&!c&&(c=Me(h/2));return(void 0!==e||void 0!==i)&&s&&l.height&&c>l.height&&(c=l.height,h=Me(Math.floor(c*s))),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Math.floor(t.height*s),o=Math.floor(t.width*s);t.height=Math.floor(t.height),t.width=Math.floor(t.width);const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function Pe(t,e){const i=be(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t){return!t||s(t.size)||s(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Ce(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function Oe(t,e,i,s){let o=(s=s||{}).data=s.data||{},a=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(o=s.data={},a=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let r=0;const l=i.length;let h,c,d,u,f;for(h=0;hi.length){for(h=0;h0&&t.stroke()}}function Re(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.xe.top-i&&t.y0&&""!==r.strokeColor;let c,d;for(t.save(),t.font=a.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]),s(e.rotation)||t.rotate(e.rotation),e.color&&(t.fillStyle=e.color),e.textAlign&&(t.textAlign=e.textAlign),e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,r),c=0;ct[0])){const o=i||t;void 0===s&&(s=ti("_fallback",t));const a={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:o,_fallback:s,_getTarget:n,override:i=>je([i,...t],e,o,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>qe(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=ti(Ue(o,t),i),void 0!==n)return Xe(t,n)?Je(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>ei(t).includes(e),ownKeys:t=>ei(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function $e(t,e,i,s){const a={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:Ye(t,s),setContext:e=>$e(t,e,i,s),override:n=>$e(t.override(n),e,i,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>qe(t,e,(()=>function(t,e,i){const{_proxy:s,_context:a,_subProxy:r,_descriptors:l}=t;let h=s[e];S(h)&&l.isScriptable(e)&&(h=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t);let l=e(o,a||s);r.delete(t),Xe(t,l)&&(l=Je(n._scopes,n,t,l));return l}(e,h,t,i));n(h)&&h.length&&(h=function(t,e,i,s){const{_proxy:n,_context:a,_subProxy:r,_descriptors:l}=i;if(void 0!==a.index&&s(t))return e[a.index%e.length];if(o(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const o of i){const i=Je(s,n,t,o);e.push($e(i,a,r&&r[t],l))}}return e}(e,h,t,l.isIndexable));Xe(e,h)&&(h=$e(h,a,r&&r[e],l));return h}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function Ye(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:S(i)?i:()=>i,isIndexable:S(s)?s:()=>s}}const Ue=(t,e)=>t?t+w(e):e,Xe=(t,e)=>o(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function qe(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];const s=i();return t[e]=s,s}function Ke(t,e,i){return S(t)?t(e,i):t}const Ge=(t,e)=>!0===t?e:"string"==typeof t?M(e,t):void 0;function Ze(t,e,i,s,n){for(const o of e){const e=Ge(i,o);if(e){t.add(e);const o=Ke(e._fallback,i,n);if(void 0!==o&&o!==i&&o!==s)return o}else if(!1===e&&void 0!==s&&i!==s)return null}return!1}function Je(t,e,i,s){const a=e._rootScopes,r=Ke(e._fallback,i,s),l=[...t,...a],h=new Set;h.add(s);let c=Qe(h,l,i,r||i,s);return null!==c&&((void 0===r||r===i||(c=Qe(h,l,r,c,s),null!==c))&&je(Array.from(h),[""],a,r,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const a=s[e];if(n(a)&&o(i))return i;return a||{}}(e,i,s))))}function Qe(t,e,i,s,n){for(;i;)i=Ze(t,e,i,s,n);return i}function ti(t,e){for(const i of e){if(!i)continue;const e=i[t];if(void 0!==e)return e}}function ei(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}function ii(t,e,i,s){const{iScale:n}=t,{key:o="r"}=this._parsing,a=new Array(s);let r,l,h,c;for(r=0,l=s;re"x"===t?"y":"x";function ai(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=q(o,n),l=q(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function ri(t,e="x"){const i=oi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=ni(t,0);for(a=0;a!t.skip))),"monotone"===e.cubicInterpolationMode)ri(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o0===t||1===t,di=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*O/i),ui=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*O/i)+1,fi={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*E),easeOutSine:t=>Math.sin(t*E),easeInOutSine:t=>-.5*(Math.cos(C*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>ci(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>ci(t)?t:di(t,.075,.3),easeOutElastic:t=>ci(t)?t:ui(t,.075,.3),easeInOutElastic(t){const e=.1125;return ci(t)?t:t<.5?.5*di(2*t,e,.45):.5+.5*ui(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-fi.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*fi.easeInBounce(2*t):.5*fi.easeOutBounce(2*t-1)+.5};function gi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function pi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function mi(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=gi(t,n,i),r=gi(n,o,i),l=gi(o,e,i),h=gi(a,r,i),c=gi(r,l,i);return gi(h,c,i)}const bi=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,xi=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function _i(t,e){const i=(""+t).match(bi);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}const yi=t=>+t||0;function vi(t,e){const i={},s=o(e),n=s?Object.keys(e):e,a=o(t)?s?i=>l(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=yi(a(t));return i}function Mi(t){return vi(t,{top:"y",right:"x",bottom:"y",left:"x"})}function wi(t){return vi(t,["topLeft","topRight","bottomLeft","bottomRight"])}function ki(t){const e=Mi(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function Si(t,e){t=t||{},e=e||ue.font;let i=l(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=l(t.style,e.style);s&&!(""+s).match(xi)&&(console.warn('Invalid font style specified: "'+s+'"'),s=void 0);const n={family:l(t.family,e.family),lineHeight:_i(l(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:l(t.weight,e.weight),string:""};return n.string=De(n),n}function Pi(t,e,i,s){let o,a,r,l=!0;for(o=0,a=t.length;oi&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ci(t,e){return Object.assign(Object.create(t),e)}function Oi(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ai(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function Ti(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Li(t){return"angle"===t?{between:Z,compare:K,normalize:G}:{between:tt,compare:(t,e)=>t-e,normalize:t=>t}}function Ei({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Ri(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Li(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Li(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;hx||l(n,b,p)&&0!==r(n,b),v=()=>!x||0===r(o,p)||l(o,b,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==b&&(x=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Ei({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,b=p));return null!==_&&g.push(Ei({start:_,end:d,loop:u,count:a,style:f})),g}function Ii(t,e){const i=[],s=t.segments;for(let n=0;nn&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Fi(t,[{start:a,end:r,loop:o}],i,e);return Fi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,r{t[a](e[i],n)&&(o.push({element:t,datasetIndex:s,index:l}),r=r||t.inRange(e.x,e.y,n))})),s&&!r?[]:o}var Xi={evaluateInteractionItems:Hi,modes:{index(t,e,i,s){const n=ve(e,t),o=i.axis||"x",a=i.includeInvisible||!1,r=i.intersect?ji(t,n,o,s,a):Yi(t,n,o,!1,s,a),l=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=r[0].index,i=t.data[e];i&&!i.skip&&l.push({element:i,datasetIndex:t.index,index:e})})),l):[]},dataset(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;let r=i.intersect?ji(t,n,o,s,a):Yi(t,n,o,!1,s,a);if(r.length>0){const e=r[0].datasetIndex,i=t.getDatasetMeta(e).data;r=[];for(let t=0;tji(t,ve(e,t),i.axis||"xy",s,i.includeInvisible||!1),nearest(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;return Yi(t,n,o,i.intersect,s,a)},x:(t,e,i,s)=>Ui(t,ve(e,t),"x",i.intersect,s),y:(t,e,i,s)=>Ui(t,ve(e,t),"y",i.intersect,s)}};const qi=["left","top","right","bottom"];function Ki(t,e){return t.filter((t=>t.pos===e))}function Gi(t,e){return t.filter((t=>-1===qi.indexOf(t.pos)&&t.box.axis===e))}function Zi(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function Ji(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!qi.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function ss(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;ot.box.fullSize)),!0),s=Zi(Ki(e,"left"),!0),n=Zi(Ki(e,"right")),o=Zi(Ki(e,"top"),!0),a=Zi(Ki(e,"bottom")),r=Gi(e,"x"),l=Gi(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Ki(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;u(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),f=Object.assign({},n);ts(f,ki(s));const g=Object.assign({maxPadding:f,w:o,h:a,x:n.left,y:n.top},n),p=Ji(l.concat(h),d);ss(r.fullSize,g,d,p),ss(l,g,d,p),ss(h,g,d,p)&&ss(l,g,d,p),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(g),os(r.leftAndTop,g,d,p),g.x+=g.w,g.y+=g.h,os(r.rightAndBottom,g,d,p),t.chartArea={left:g.left,top:g.top,right:g.left+g.w,bottom:g.top+g.h,height:g.h,width:g.w},u(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(g.w,g.h,{left:0,top:0,right:0,bottom:0})}))}};class rs{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,s){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,s?Math.floor(e/s):i)}}isAttached(t){return!0}updateConfig(t){}}class ls extends rs{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const hs="$chartjs",cs={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},ds=t=>null===t||""===t;const us=!!Se&&{passive:!0};function fs(t,e,i){t.canvas.removeEventListener(e,i,us)}function gs(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function ps(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||gs(i.addedNodes,s),e=e&&!gs(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function ms(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||gs(i.removedNodes,s),e=e&&!gs(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const bs=new Map;let xs=0;function _s(){const t=window.devicePixelRatio;t!==xs&&(xs=t,bs.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function ys(t,e,i){const s=t.canvas,n=s&&ge(s);if(!n)return;const o=ct(((t,e)=>{const s=n.clientWidth;i(t,e),s{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||o(i,s)}));return a.observe(n),function(t,e){bs.size||window.addEventListener("resize",_s),bs.set(t,e)}(t,o),a}function vs(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){bs.delete(t),bs.size||window.removeEventListener("resize",_s)}(t)}function Ms(t,e,i){const s=t.canvas,n=ct((e=>{null!==t.ctx&&i(function(t,e){const i=cs[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t);return function(t,e,i){t.addEventListener(e,i,us)}(s,e,n),n}class ws extends rs{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t[hs]={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",ds(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(ds(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e[hs])return!1;const i=e[hs].initial;["height","width"].forEach((t=>{const n=i[t];s(n)?e.removeAttribute(t):e.setAttribute(t,n)}));const n=i.style||{};return Object.keys(n).forEach((t=>{e.style[t]=n[t]})),e.width=e.width,delete e[hs],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:ps,detach:ms,resize:ys}[e]||Ms;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:vs,detach:vs,resize:vs}[e]||fs)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return we(t,e,i,s)}isAttached(t){const e=ge(t);return!(!e||!e.isConnected)}}function ks(t){return!fe()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?ls:ws}var Ss=Object.freeze({__proto__:null,BasePlatform:rs,BasicPlatform:ls,DomPlatform:ws,_detectPlatform:ks});const Ps="transparent",Ds={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=Qt(t||Ps),n=s.valid&&Qt(e||Ps);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class Cs{constructor(t,e,i,s){const n=e[i];s=Pi([t.to,s,n,t.from]);const o=Pi([t.from,n,s]);this._active=!0,this._fn=t.fn||Ds[t.type||typeof o],this._easing=fi[t.easing]||fi.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=Pi([t.to,e,s,t.from]),this._from=Pi([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t{const a=t[s];if(!o(a))return;const r={};for(const t of e)r[t]=a[t];(n(a.properties)&&a.properties||[s]).forEach((t=>{t!==s&&i.has(t)||i.set(t,r)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new Cs(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(xt.add(this._chart,i),!0):void 0}}function As(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function Ts(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n0||!i&&e<0)return n.index}return null}function zs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;ti[t].axis===e)).shift()}function Vs(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i],void 0!==e[s]._visualValues&&void 0!==e[s]._visualValues[i]&&delete e[s]._visualValues[i]}}}const Bs=t=>"reset"===t||"none"===t,Ws=(t,e)=>e?t:Object.assign({},t);class Ns{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Es(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&Vs(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=l(i.xAxisID,Fs(t,"x")),o=e.yAxisID=l(i.yAxisID,Fs(t,"y")),a=e.rAxisID=l(i.rAxisID,Fs(t,"r")),r=e.indexAxis,h=e.iAxisID=s(r,n,o,a),c=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(h),e.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&rt(this._data,this),t._stacked&&Vs(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(o(e))this._data=function(t){const e=Object.keys(t),i=new Array(e.length);let s,n,o;for(s=0,n=e.length;s0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,d=s;else{d=n(s[t])?this.parseArrayData(i,s,t,e):o(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const a=()=>null===c[l]||f&&c[l]t&&!e.hidden&&e._stacked&&{keys:Ts(i,!0),values:null})(e,i,this.chart),h={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(r);let u,f;function g(){f=s[u];const e=f[r.axis];return!a(f[t.axis])||c>e||d=0;--u)if(!g()){this.updateRangeFromParsed(h,t,f,l);break}return h}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s=0&&tthis.getContext(i,s,e)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Ws(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new Os(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||Bs(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){const i=this.resolveDataElementOptions(t,e),s=this._sharedOptions,n=this.getSharedOptions(i),o=this.includeOptions(e,n)||n!==s;return this.updateSharedOptions(n,e,i),{sharedOptions:n,includeOptions:o}}updateElement(t,e,i,s){Bs(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!Bs(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}function js(t,e){const i=t.options.ticks,n=function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),o=Math.min(i.maxTicksLimit||n,n),a=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;io)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;nn)return e}return Math.max(n,1)}(a,e,o);if(r>0){let t,i;const n=r>1?Math.round((h-l)/(r-1)):null;for($s(e,c,d,s(n)?0:l-n,l),t=0,i=r-1;t"top"===e||"left"===e?t[e]+i:t[e]-i,Us=(t,e)=>Math.min(e||t,t);function Xs(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;oa+r)))return h}function Ks(t){return t.drawTicks?t.tickLength:0}function Gs(t,e){if(!t.display)return 0;const i=Si(t.font,e),s=ki(t.padding);return(n(t.text)?t.text.length:1)*i.lineHeight+s.height}function Zs(t,e,i){let s=ut(t);return(i&&"right"!==e||!i&&"right"===e)&&(s=(t=>"left"===t?"right":"right"===t?"left":t)(s)),s}class Js extends Hs{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=r(t,Number.POSITIVE_INFINITY),e=r(e,Number.NEGATIVE_INFINITY),i=r(i,Number.POSITIVE_INFINITY),s=r(s,Number.NEGATIVE_INFINITY),{min:r(t,i),max:r(e,s),minDefined:a(t),maxDefined:a(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;rs?s:i,s=n&&i>s?i:s,{min:r(i,r(s,i)),max:r(s,r(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=Di(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=J(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Ks(t.grid)-e.padding-Gs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=Y(Math.min(Math.asin(J((h.highest.height+6)/o,-1,1)),Math.asin(J(a/r,-1,1))-Math.asin(J(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=Gs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Ks(n)+o):(t.height=this.maxHeight,t.width=Ks(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=$(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:"inner"!==n&&(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n({width:r[t]||0,height:l[t]||0});return{first:P(0),last:P(e-1),widest:P(k),highest:P(S),widths:r,heights:l}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return Q(this._alignToPixels?Ae(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&ta*s?a/i:r/s:r*s0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:a,border:r}=s,h=n.offset,c=this.isHorizontal(),d=this.ticks.length+(h?1:0),u=Ks(n),f=[],g=r.setContext(this.getContext()),p=g.display?g.width:0,m=p/2,b=function(t){return Ae(i,t,p)};let x,_,y,v,M,w,k,S,P,D,C,O;if("top"===a)x=b(this.bottom),w=this.bottom-u,S=x-m,D=b(t.top)+m,O=t.bottom;else if("bottom"===a)x=b(this.top),D=t.top,O=b(t.bottom)-m,w=x+m,S=this.top+u;else if("left"===a)x=b(this.right),M=this.right-u,k=x-m,P=b(t.left)+m,C=t.right;else if("right"===a)x=b(this.left),P=t.left,C=b(t.right)-m,M=x+m,k=this.left+u;else if("x"===e){if("center"===a)x=b((t.top+t.bottom)/2+.5);else if(o(a)){const t=Object.keys(a)[0],e=a[t];x=b(this.chart.scales[t].getPixelForValue(e))}D=t.top,O=t.bottom,w=x+m,S=w+u}else if("y"===e){if("center"===a)x=b((t.left+t.right)/2);else if(o(a)){const t=Object.keys(a)[0],e=a[t];x=b(this.chart.scales[t].getPixelForValue(e))}M=x-m,k=M-u,P=t.left,C=t.right}const A=l(s.ticks.maxTicksLimit,d),T=Math.max(1,Math.ceil(d/A));for(_=0;_e.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:s,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");ue.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&ue.describe(e,t.descriptors)}(t,o,i),this.override&&ue.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in ue[s]&&(delete ue[s][i],this.override&&delete re[i])}}class tn{constructor(){this.controllers=new Qs(Ns,"datasets",!0),this.elements=new Qs(Hs,"elements"),this.plugins=new Qs(Object,"plugins"),this.scales=new Qs(Js,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):u(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=w(t);d(i["before"+s],[],i),e[t](i),d(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;et.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function nn(t,e){return e||!1!==t?!0===t?{}:t:null}function on(t,{plugin:e,local:i},s,n){const o=t.pluginScopeKeys(e),a=t.getOptionScopes(s,o);return i&&e.defaults&&a.push(e.defaults),t.createResolver(a,n,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function an(t,e){const i=ue.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function rn(t){if("x"===t||"y"===t||"r"===t)return t}function ln(t,...e){if(rn(t))return t;for(const s of e){const e=s.axis||("top"===(i=s.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.length>1&&rn(t[0].toLowerCase());if(e)return e}var i;throw new Error(`Cannot determine type of '${t}' axis. Please provide 'axis' or 'position' option.`)}function hn(t,e,i){if(i[e+"AxisID"]===t)return{axis:e}}function cn(t,e){const i=re[t.type]||{scales:{}},s=e.scales||{},n=an(t.type,e),a=Object.create(null);return Object.keys(s).forEach((e=>{const r=s[e];if(!o(r))return console.error(`Invalid scale configuration for scale: ${e}`);if(r._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${e}`);const l=ln(e,r,function(t,e){if(e.data&&e.data.datasets){const i=e.data.datasets.filter((e=>e.xAxisID===t||e.yAxisID===t));if(i.length)return hn(t,"x",i[0])||hn(t,"y",i[0])}return{}}(e,t),ue.scales[r.type]),h=function(t,e){return t===e?"_index_":"_value_"}(l,n),c=i.scales||{};a[e]=x(Object.create(null),[{axis:l},r,c[l],c[h]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,o=i.indexAxis||an(n,e),r=(re[n]||{}).scales||{};Object.keys(r).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,o),n=i[e+"AxisID"]||e;a[n]=a[n]||Object.create(null),x(a[n],[{axis:e},s[n],r[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];x(e,[ue.scales[e.type],ue.scale])})),a}function dn(t){const e=t.options||(t.options={});e.plugins=l(e.plugins,{}),e.scales=cn(t,e)}function un(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const fn=new Map,gn=new Set;function pn(t,e){let i=fn.get(t);return i||(i=e(),fn.set(t,i),gn.add(i)),i}const mn=(t,e,i)=>{const s=M(e,i);void 0!==s&&t.add(s)};class bn{constructor(t){this._config=function(t){return(t=t||{}).data=un(t.data),dn(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=un(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),dn(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return pn(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return pn(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return pn(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return pn(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>mn(r,t,e)))),e.forEach((t=>mn(r,s,t))),e.forEach((t=>mn(r,re[n]||{},t))),e.forEach((t=>mn(r,ue,t))),e.forEach((t=>mn(r,le,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),gn.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,re[e]||{},ue.datasets[e]||{},{type:e},ue,le]}resolveNamedOptions(t,e,i,s=[""]){const o={$shared:!0},{resolver:a,subPrefixes:r}=xn(this._resolverCache,t,s);let l=a;if(function(t,e){const{isScriptable:i,isIndexable:s}=Ye(t);for(const o of e){const e=i(o),a=s(o),r=(a||e)&&t[o];if(e&&(S(r)||_n(r))||a&&n(r))return!0}return!1}(a,e)){o.$shared=!1;l=$e(a,i=S(i)?i():i,this.createResolver(t,i,r))}for(const t of e)o[t]=l[t];return o}createResolver(t,e,i=[""],s){const{resolver:n}=xn(this._resolverCache,t,i);return o(e)?$e(n,e,void 0,s):n}}function xn(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:je(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const _n=t=>o(t)&&Object.getOwnPropertyNames(t).reduce(((e,i)=>e||S(t[i])),!1);const yn=["top","bottom","left","right","chartArea"];function vn(t,e){return"top"===t||"bottom"===t||-1===yn.indexOf(t)&&"x"===e}function Mn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function wn(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),d(i&&i.onComplete,[t],e)}function kn(t){const e=t.chart,i=e.options.animation;d(i&&i.onProgress,[t],e)}function Sn(t){return fe()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const Pn={},Dn=t=>{const e=Sn(t);return Object.values(Pn).filter((t=>t.canvas===e)).pop()};function Cn(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class On{static defaults=ue;static instances=Pn;static overrides=re;static registry=en;static version="4.3.3";static getChart=Dn;static register(...t){en.add(...t),An()}static unregister(...t){en.remove(...t),An()}constructor(t,e){const s=this.config=new bn(e),n=Sn(t),o=Dn(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const a=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||ks(n)),this.platform.updateConfig(s);const r=this.platform.acquireContext(n,a.aspectRatio),l=r&&r.canvas,h=l&&l.height,c=l&&l.width;this.id=i(),this.ctx=r,this.canvas=l,this.width=c,this.height=h,this._options=a,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new sn,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=dt((t=>this.update(t)),a.resizeDelay||0),this._dataChanges=[],Pn[this.id]=this,r&&l?(xt.listen(this,"complete",wn),xt.listen(this,"progress",kn),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:n,_aspectRatio:o}=this;return s(t)?e&&o?o:n?i/n:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return en}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Te(this.canvas,this.ctx),this}stop(){return xt.stop(this),this}resize(t,e){xt.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),d(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){u(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=ln(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),u(n,(e=>{const n=e.options,o=n.id,a=ln(o,n),r=l(n.type,e.dtype);void 0!==n.position&&vn(n.position,a)===vn(e.dposition)||(n.position=e.dposition),s[o]=!0;let h=null;if(o in i&&i[o].type===r)h=i[o];else{h=new(en.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[h.id]=h}h.init(n,t)})),u(s,((t,e)=>{t||delete i[e]})),u(i,(t=>{as.configure(this,t,t.options),as.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;te.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(Mn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){u(this.scales,(t=>{as.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);P(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){Cn(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;tt.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;as.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],u(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i=t._clip,s=!i.disabled,n=function(t){const{xScale:e,yScale:i}=t;if(e&&i)return{left:e.left,right:e.right,top:i.top,bottom:i.bottom}}(t)||this.chartArea,o={meta:t,index:t.index,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetDraw",o)&&(s&&Ie(e,{left:!1===i.left?0:n.left-i.left,right:!1===i.right?this.width:n.right+i.right,top:!1===i.top?0:n.top-i.top,bottom:!1===i.bottom?this.height:n.bottom+i.bottom}),t.controller.draw(),s&&ze(e),o.cancelable=!1,this.notifyPlugins("afterDatasetDraw",o))}isPointInArea(t){return Re(t,this.chartArea,this._minPadding)}getElementsAtEventForMode(t,e,i,s){const n=Xi.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ci(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);k(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),xt.remove(this),t=0,e=this.data.datasets.length;t{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};u(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){u(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},u(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!f(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(t){return 1===this._plugins._cache.filter((e=>e.plugin.id===t)).length}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:this.isPointInArea(t)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=D(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,d(n.onHover,[t,a,this],this),r&&d(n.onClick,[t,a,this],this));const h=!f(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}function An(){return u(On.instances,(t=>t._plugins.invalidate()))}function Tn(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Ln{static override(t){Object.assign(Ln.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return Tn()}parse(){return Tn()}format(){return Tn()}add(){return Tn()}diff(){return Tn()}startOf(){return Tn()}endOf(){return Tn()}}var En={_date:Ln};function Rn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;et-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(k(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;sMath.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function zn(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;ht.x,i="left",s="right"):(e=t.base"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i,color:s}}=t.legend.options;return e.labels.map(((e,n)=>{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,a,r=t=>+i[t];if(o(i[t])){const{key:t="value"}=this._parsing;r=e=>+M(i[e],t)}for(n=t,a=t+e;nZ(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>Z(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(E,c,u),b=g(C,h,d),x=g(C+E,c,u);s=(p-b)/2,n=(m-x)/2,o=-(p+b)/2,a=-(m+x)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(u,d,r),b=(i.width-o)/f,x=(i.height-o)/g,_=Math.max(Math.min(b,x)/2,0),y=c(this.options.radius,_),v=(y-Math.max(y*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=p*y,this.offsetY=m*y,s.total=this.calculateTotal(),this.outerRadius=y-v*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-v*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/O)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,{sharedOptions:f,includeOptions:g}=this._getSharedOptions(e,s);let p,m=this._getRotation();for(p=0;p0&&!isNaN(t)?O*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,e={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach(((t,i)=>{const s=this.getParsed(i).r;!isNaN(s)&&this.chart.getDataVisibility(i)&&(se.max&&(e.max=s))})),e}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.options.animation,r=this._cachedMeta.rScale,l=r.xCenter,h=r.yCenter,c=r.getIndexAngle(0)-.5*C;let d,u=c;const f=360/this.countVisibleElements();for(d=0;d{!isNaN(this.getParsed(i).r)&&this.chart.getDataVisibility(i)&&e++})),e}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?$(this.resolveDataElementOptions(t,e).angle||i):0}}var $n=Object.freeze({__proto__:null,BarController:class extends Ns{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(t,e,i,s){return zn(t,e,i,s)}parseArrayData(t,e,i,s){return zn(t,e,i,s)}parseObjectData(t,e,i,s){const{iScale:n,vScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l="x"===n.axis?a:r,h="x"===o.axis?a:r,c=[];let d,u,f,g;for(d=i,u=i+s;dt.controller.options.grouped)),o=i.options.stacked,a=[],r=t=>{const i=t.controller.getParsed(e),n=i&&i[t.vScale.axis];if(s(n)||isNaN(n))return!0};for(const i of n)if((void 0===e||!r(i))&&((!1===o||-1===a.indexOf(i.stack)||void 0===o&&void 0===i.stack)&&a.push(i.stack),i.index===t))break;return a.length||a.push(void 0),a}_getStackCount(t){return this._getStacks(void 0,t).length}_getStackIndex(t,e,i){const s=this._getStacks(t,i),n=void 0!==e?s.indexOf(e):-1;return-1===n?s.length-1:n}_getRuler(){const t=this.options,e=this._cachedMeta,i=e.iScale,s=[];let n,o;for(n=0,o=e.data.length;n=i?1:-1)}(u,e,r)*a,f===r&&(b-=u/2);const t=e.getPixelForDecimal(0),s=e.getPixelForDecimal(1),o=Math.min(t,s),h=Math.max(t,s);b=Math.max(Math.min(b,h),o),d=b+u,i&&!c&&(l._stacks[e.axis]._visualValues[n]=e.getValueForPixel(d)-e.getValueForPixel(b))}if(b===e.getPixelForValue(r)){const t=F(u)*e.getLineWidthForValue(r)/2;b+=t,u-=t}return{size:u,base:b,head:d,center:d+u/2}}_calculateBarIndexPixels(t,e){const i=e.scale,n=this.options,o=n.skipNull,a=l(n.maxBarThickness,1/0);let r,h;if(e.grouped){const i=o?this._getStackCount(t):e.stackCount,l="flex"===n.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y),l=o._custom;return{label:i[t]||"",value:"("+a+", "+r+(l?", "+l:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,{sharedOptions:r,includeOptions:l}=this._getSharedOptions(e,s),h=o.axis,c=a.axis;for(let d=e;d0&&this.getParsed(e-1);for(let i=0;i<_;++i){const g=t[i],_=b?g:{};if(i=x){_.skip=!0;continue}const v=this.getParsed(i),M=s(v[f]),w=_[u]=a.getPixelForValue(v[u],i),k=_[f]=o||M?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,v,l):v[f],i);_.skip=isNaN(w)||isNaN(k)||M,_.stop=i>0&&Math.abs(v[u]-y[u])>m,p&&(_.parsed=v,_.raw=h.data[i]),d&&(_.options=c||this.resolveDataElementOptions(i,g.active?"active":n)),b||this.updateElement(g,i,_,n),y=v}}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}},PieController:class extends Hn{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:jn,RadarController:class extends Ns{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this._cachedMeta.rScale,o="reset"===s;for(let a=e;a0&&this.getParsed(e-1);for(let c=e;c0&&Math.abs(i[f]-_[f])>b,m&&(p.parsed=i,p.raw=h.data[c]),u&&(p.options=d||this.resolveDataElementOptions(c,e.active?"active":n)),x||this.updateElement(e,c,p,n),_=i}this.updateSharedOptions(d,n,c)}getMaxOverflow(){const t=this._cachedMeta,e=t.data||[];if(!this.options.showLine){let t=0;for(let i=e.length-1;i>=0;--i)t=Math.max(t,e[i].size(this.resolveDataElementOptions(i))/2);return t>0&&t}const i=t.dataset,s=i.options&&i.options.borderWidth||0;if(!e.length)return s;const n=e[0].size(this.resolveDataElementOptions(0)),o=e[e.length-1].size(this.resolveDataElementOptions(e.length-1));return Math.max(s,n,o)/2}}});function Yn(t,e,i,s){const n=vi(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return J(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:J(n.innerStart,0,a),innerEnd:J(n.innerEnd,0,a)}}function Un(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Xn(t,e,i,s,n,o){const{x:a,y:r,startAngle:l,pixelMargin:h,innerRadius:c}=e,d=Math.max(e.outerRadius+s+i-h,0),u=c>0?c+s+i+h:0;let f=0;const g=n-l;if(s){const t=((c>0?c-s:0)+(d>0?d-s:0))/2;f=(g-(0!==t?g*t/(t+s):g))/2}const p=(g-Math.max(.001,g*d-i/C)/d)/2,m=l+p+f,b=n-p-f,{outerStart:x,outerEnd:_,innerStart:y,innerEnd:v}=Yn(e,u,d,b-m),M=d-x,w=d-_,k=m+x/M,S=b-_/w,P=u+y,D=u+v,O=m+y/P,A=b-v/D;if(t.beginPath(),o){const e=(k+S)/2;if(t.arc(a,r,d,k,e),t.arc(a,r,d,e,S),_>0){const e=Un(w,S,a,r);t.arc(e.x,e.y,_,S,b+E)}const i=Un(D,b,a,r);if(t.lineTo(i.x,i.y),v>0){const e=Un(D,A,a,r);t.arc(e.x,e.y,v,b+E,A+Math.PI)}const s=(b-v/u+(m+y/u))/2;if(t.arc(a,r,u,b-v/u,s,!0),t.arc(a,r,u,s,m+y/u,!0),y>0){const e=Un(P,O,a,r);t.arc(e.x,e.y,y,O+Math.PI,m-E)}const n=Un(M,m,a,r);if(t.lineTo(n.x,n.y),x>0){const e=Un(M,k,a,r);t.arc(e.x,e.y,x,m-E,k)}}else{t.moveTo(a,r);const e=Math.cos(k)*d+a,i=Math.sin(k)*d+r;t.lineTo(e,i);const s=Math.cos(S)*d+a,n=Math.sin(S)*d+r;t.lineTo(s,n)}t.closePath()}function qn(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r,options:l}=e,{borderWidth:h,borderJoinStyle:c,borderDash:d,borderDashOffset:u}=l,f="inner"===l.borderAlign;if(!h)return;t.setLineDash(d||[]),t.lineDashOffset=u,f?(t.lineWidth=2*h,t.lineJoin=c||"round"):(t.lineWidth=h,t.lineJoin=c||"bevel");let g=e.endAngle;if(o){Xn(t,e,i,s,g,n);for(let e=0;en?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+E,s-E),t.closePath(),t.clip()}(t,e,g),o||(Xn(t,e,i,s,g,n),t.stroke())}function Kn(t,e,i=e){t.lineCap=l(i.borderCapStyle,e.borderCapStyle),t.setLineDash(l(i.borderDash,e.borderDash)),t.lineDashOffset=l(i.borderDashOffset,e.borderDashOffset),t.lineJoin=l(i.borderJoinStyle,e.borderJoinStyle),t.lineWidth=l(i.borderWidth,e.borderWidth),t.strokeStyle=l(i.borderColor,e.borderColor)}function Gn(t,e,i){t.lineTo(i.x,i.y)}function Zn(t,e,i={}){const s=t.length,{start:n=0,end:o=s-1}=i,{start:a,end:r}=e,l=Math.max(n,a),h=Math.min(o,r),c=nr&&o>r;return{count:s,start:l,loop:e.loop,ilen:h(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[x(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[x(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(ig&&(g=i),m=(b*m+e)/++b):(_(),t.lineTo(e,i),u=s,b=0,f=g=i),p=i}_()}function to(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?Qn:Jn}const eo="function"==typeof Path2D;function io(t,e,i,s){eo&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Kn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=to(e);for(const r of n)Kn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class so extends Hs{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;hi(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=zi(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Ii(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?pi:t.tension||"monotone"===t.cubicInterpolationMode?mi:gi}(i);let l,h;for(l=0,h=o.length;l"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.getProps(["x","y"],i),{angle:n,distance:o}=X(s,{x:t,y:e}),{startAngle:a,endAngle:r,innerRadius:h,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),u=(this.options.spacing+this.options.borderWidth)/2,f=l(d,r-a)>=O||Z(n,a,r),g=tt(o,h+u,c+u);return f&&g}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/4,n=(e.spacing||0)/2,o=e.circular;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>O?Math.floor(i/O):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();const a=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(a)*s,Math.sin(a)*s);const r=s*(1-Math.sin(Math.min(C,i||0)));t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor,function(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r}=e;let l=e.endAngle;if(o){Xn(t,e,i,s,l,n);for(let e=0;e("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}function go(t){const e=this.getLabels();return t>=0&&ts=e?s:t,a=t=>n=i?n:t;if(t){const t=F(s),e=F(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=0===n?1:Math.abs(.05*n);a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const n=function(t,e){const i=[],{bounds:n,step:o,min:a,max:r,precision:l,count:h,maxTicks:c,maxDigits:d,includeBounds:u}=t,f=o||1,g=c-1,{min:p,max:m}=e,b=!s(a),x=!s(r),_=!s(h),y=(m-p)/(d+1);let v,M,w,k,S=B((m-p)/g/f)*f;if(S<1e-14&&!b&&!x)return[{value:p},{value:m}];k=Math.ceil(m/S)-Math.floor(p/S),k>g&&(S=B(k*S/g/f)*f),s(l)||(v=Math.pow(10,l),S=Math.ceil(S*v)/v),"ticks"===n?(M=Math.floor(p/S)*S,w=Math.ceil(m/S)*S):(M=p,w=m),b&&x&&o&&H((r-a)/o,S/1e3)?(k=Math.round(Math.min((r-a)/S,c)),S=(r-a)/k,M=a,w=r):_?(M=b?a:M,w=x?r:w,k=h-1,S=(w-M)/k):(k=(w-M)/S,k=V(k,Math.round(k),S/1e3)?Math.round(k):Math.ceil(k));const P=Math.max(U(S),U(M));v=Math.pow(10,s(l)?P:l),M=Math.round(M*v)/v,w=Math.round(w*v)/v;let D=0;for(b&&(u&&M!==a?(i.push({value:a}),Mr)break;i.push({value:t})}return x&&u&&w!==r?i.length&&V(i[i.length-1].value,r,po(r,y,t))?i[i.length-1].value=r:i.push({value:r}):x&&w!==r||i.push({value:w}),i}({maxTicks:i,bounds:t.bounds,min:t.min,max:t.max,precision:e.precision,step:e.stepSize,count:e.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:e.minRotation||0,includeBounds:!1!==e.includeBounds},this._range||this);return"ticks"===t.bounds&&j(n,this,"value"),t.reverse?(n.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),n}configure(){const t=this.ticks;let e=this.min,i=this.max;if(super.configure(),this.options.offset&&t.length){const s=(i-e)/Math.max(t.length-1,1)/2;e-=s,i+=s}this._startValue=e,this._endValue=i,this._valueRange=i-e}getLabelForValue(t){return ne(t,this.chart.options.locale,this.options.ticks.format)}}class bo extends mo{static id="linear";static defaults={ticks:{callback:ae.formatters.numeric}};determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?t:0,this.max=a(e)?e:1,this.handleTickRangeOptions()}computeTickLimit(){const t=this.isHorizontal(),e=t?this.width:this.height,i=$(this.options.ticks.minRotation),s=(t?Math.sin(i):Math.cos(i))||.001,n=this._resolveTickFontOptions(0);return Math.ceil(e/Math.min(40,n.lineHeight/s))}getPixelForValue(t){return null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const xo=t=>Math.floor(z(t)),_o=(t,e)=>Math.pow(10,xo(t)+e);function yo(t){return 1===t/Math.pow(10,xo(t))}function vo(t,e,i){const s=Math.pow(10,i),n=Math.floor(t/s);return Math.ceil(e/s)-n}function Mo(t,{min:e,max:i}){e=r(t.min,e);const s=[],n=xo(e);let o=function(t,e){let i=xo(e-t);for(;vo(t,e,i)>10;)i++;for(;vo(t,e,i)<10;)i--;return Math.min(i,xo(t))}(e,i),a=o<0?Math.pow(10,Math.abs(o)):1;const l=Math.pow(10,o),h=n>o?Math.pow(10,n):0,c=Math.round((e-h)*a)/a,d=Math.floor((e-h)/l/10)*l*10;let u=Math.floor((c-d)/Math.pow(10,o)),f=r(t.min,Math.round((h+d+u*Math.pow(10,o))*a)/a);for(;f=10?u=u<15?15:20:u++,u>=20&&(o++,u=2,a=o>=0?1:a),f=Math.round((h+d+u*Math.pow(10,o))*a)/a;const g=r(t.max,f);return s.push({value:g,major:yo(g),significand:u}),s}class wo extends Js{static id="logarithmic";static defaults={ticks:{callback:ae.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,e){const i=mo.prototype.parse.apply(this,[t,e]);if(0!==i)return a(i)&&i>0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?Math.max(0,t):null,this.max=a(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!a(this._userMin)&&(this.min=t===_o(this.min,0)?_o(this.min,-1):_o(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t;i===s&&(i<=0?(n(1),o(10)):(n(_o(i,-1)),o(_o(s,1)))),i<=0&&n(_o(s,-1)),s<=0&&o(_o(i,1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=Mo({min:this._userMin,max:this._userMax},this);return"ticks"===t.bounds&&j(e,this,"value"),t.reverse?(e.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),e}getLabelForValue(t){return void 0===t?"0":ne(t,this.chart.options.locale,this.options.ticks.format)}configure(){const t=this.min;super.configure(),this._startValue=z(t),this._valueRange=z(this.max)-z(t)}getPixelForValue(t){return void 0!==t&&0!==t||(t=this.min),null===t||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(z(t)-this._startValue)/this._valueRange)}getValueForPixel(t){const e=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+e*this._valueRange)}}function ko(t){const e=t.ticks;if(e.display&&t.display){const t=ki(e.backdropPadding);return l(e.font&&e.font.size,ue.font.size)+t.height}return 0}function So(t,e,i,s,n){return t===s||t===n?{start:e-i/2,end:e+i/2}:tn?{start:e-i,end:e}:{start:e,end:e+i}}function Po(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],o=[],a=t._pointLabels.length,r=t.options.pointLabels,l=r.centerPointLabels?C/a:0;for(let u=0;ue.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.starte.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function Co(t,e,i){const s=t.drawingArea,{extra:n,additionalAngle:o,padding:a,size:r}=i,l=t.getPointPosition(e,s+n+a,o),h=Math.round(Y(G(l.angle+E))),c=function(t,e,i){90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e);return t}(l.y,r.h,h),d=function(t){if(0===t||180===t)return"center";if(t<180)return"left";return"right"}(h),u=function(t,e,i){"right"===i?t-=e:"center"===i&&(t-=e/2);return t}(l.x,r.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:u,top:c,right:u+r.w,bottom:c+r.h}}function Oo(t,e){if(!e)return!0;const{left:i,top:s,right:n,bottom:o}=t;return!(Re({x:i,y:s},e)||Re({x:i,y:o},e)||Re({x:n,y:s},e)||Re({x:n,y:o},e))}function Ao(t,e,i){const{left:n,top:o,right:a,bottom:r}=i,{backdropColor:l}=e;if(!s(l)){const i=wi(e.borderRadius),s=ki(e.backdropPadding);t.fillStyle=l;const h=n-s.left,c=o-s.top,d=a-n+s.width,u=r-o+s.height;Object.values(i).some((t=>0!==t))?(t.beginPath(),He(t,{x:h,y:c,w:d,h:u,radius:i}),t.fill()):t.fillRect(h,c,d,u)}}function To(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,O);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;ot,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(t){super(t),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const t=this._padding=ki(ko(this.options)/2),e=this.width=this.maxWidth-t.width,i=this.height=this.maxHeight-t.height;this.xCenter=Math.floor(this.left+e/2+t.left),this.yCenter=Math.floor(this.top+i/2+t.top),this.drawingArea=Math.floor(Math.min(e,i)/2)}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!1);this.min=a(t)&&!isNaN(t)?t:0,this.max=a(e)&&!isNaN(e)?e:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/ko(this.options))}generateTickLabels(t){mo.prototype.generateTickLabels.call(this,t),this._pointLabels=this.getLabels().map(((t,e)=>{const i=d(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?Po(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return G(t*(O/(this._pointLabels.length||1))+$(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if(s(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(s(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t=0;n--){const e=t._pointLabelItems[n];if(!e.visible)continue;const o=s.setContext(t.getPointLabelContext(n));Ao(i,o,e);const a=Si(o.font),{x:r,y:l,textAlign:h}=e;Ne(i,t._pointLabels[n],r,l+a.lineHeight/2,a,{color:o.color,textAlign:h,textBaseline:"middle"})}}(this,o),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e){r=this.getDistanceFromCenterForValue(t.value);const i=this.getContext(e),a=s.setContext(i),l=n.setContext(i);!function(t,e,i,s,n){const o=t.ctx,a=e.circular,{color:r,lineWidth:l}=e;!a&&!s||!r||!l||i<0||(o.save(),o.strokeStyle=r,o.lineWidth=l,o.setLineDash(n.dash),o.lineDashOffset=n.dashOffset,o.beginPath(),To(t,i,a,s),o.closePath(),o.stroke(),o.restore())}(this,a,r,o,l)}})),i.display){for(t.save(),a=o-1;a>=0;a--){const s=i.setContext(this.getPointLabelContext(a)),{color:n,lineWidth:o}=s;o&&n&&(t.lineWidth=o,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,r=this.getDistanceFromCenterForValue(e.ticks.reverse?this.min:this.max),l=this.getPointPosition(a,r),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(l.x,l.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=Si(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=ki(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}Ne(t,s.label,0,-n,l,{color:r.color,strokeColor:r.textStrokeColor,strokeWidth:r.textStrokeWidth})})),t.restore()}drawTitle(){}}const Eo={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},Ro=Object.keys(Eo);function Io(t,e){return t-e}function zo(t,e){if(s(e))return null;const i=t._adapter,{parser:n,round:o,isoWeekday:r}=t._parseOpts;let l=e;return"function"==typeof n&&(l=n(l)),a(l)||(l="string"==typeof n?i.parse(l,n):i.parse(l)),null===l?null:(o&&(l="week"!==o||!N(r)&&!0!==r?i.startOf(l,o):i.startOf(l,"isoWeek",r)),+l)}function Fo(t,e,i,s){const n=Ro.length;for(let o=Ro.indexOf(t);o=e?i[s]:i[n]]=!0}}else t[e]=!0}function Bo(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a=0&&(e[l].major=!0);return e}(t,s,n,i):s}class Wo extends Js{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e={}){const i=t.time||(t.time={}),s=this._adapter=new En._date(t.adapters.date);s.init(e),x(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:zo(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:r}=this.getUserBounds();function l(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),r||isNaN(t.max)||(n=Math.max(n,t.max))}o&&r||(l(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||l(this.getMinMax(!1))),s=a(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=a(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=nt(s,n,this.max);return this._unit=e.unit||(i.autoSkip?Fo(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=Ro.length-1;o>=Ro.indexOf(i);o--){const i=Ro[o];if(Eo[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return Ro[i?Ro.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=Ro.indexOf(t)+1,i=Ro.length;e+t.value)))}initOffsets(t=[]){let e,i,s=0,n=0;this.options.offset&&t.length&&(e=this.getDecimalForValue(t[0]),s=1===t.length?1-e:(this.getDecimalForValue(t[1])-e)/2,i=this.getDecimalForValue(t[t.length-1]),n=1===t.length?i:(i-this.getDecimalForValue(t[t.length-2]))/2);const o=t.length<3?.5:.25;s=J(s,0,o),n=J(n,0,o),this._offsets={start:s,end:n,factor:1/(s+1+n)}}_generate(){const t=this._adapter,e=this.min,i=this.max,s=this.options,n=s.time,o=n.unit||Fo(n.minUnit,e,i,this._getLabelCapacity(e)),a=l(s.ticks.stepSize,1),r="week"===o&&n.isoWeekday,h=N(r)||!0===r,c={};let d,u,f=e;if(h&&(f=+t.startOf(f,"isoWeek",r)),f=+t.startOf(f,h?"day":o),t.diff(i,e,o)>1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const g="data"===s.ticks.source&&this.getDataTimestamps();for(d=f,u=0;d+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){const i=this.options.time.displayFormats,s=this._unit,n=e||i[s];return this._adapter.format(t,n)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.ticks.callback;if(o)return d(o,[t,e,i],this);const a=n.time.displayFormats,r=this._unit,l=this._majorUnit,h=r&&a[r],c=l&&a[l],u=i[e],f=l&&c&&u&&u.major;return this._adapter.format(t,s||(f?c:h))}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=it(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=it(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}var Ho=Object.freeze({__proto__:null,CategoryScale:class extends Js{static id="category";static defaults={ticks:{callback:go}};constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if(s(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:J(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:fo(i,t,l(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){return go.call(this,t)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(t){return"number"!=typeof t&&(t=this.parse(t)),null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:bo,LogarithmicScale:wo,RadialLinearScale:Lo,TimeScale:Wo,TimeSeriesScale:class extends Wo{static id="timeseries";static defaults=Wo.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=No(e,this.min),this._tableRange=No(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;ot-e))}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const e=this.getDataTimestamps(),i=this.getLabelTimestamps();return t=e.length&&i.length?this.normalize(e.concat(i)):e.length?e:i,t=this._cache.all=t,t}getDecimalForValue(t){return(No(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return No(this._table,i*this._tableRange+this._minPos,!0)}}});const jo=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],$o=jo.map((t=>t.replace("rgb(","rgba(").replace(")",", 0.5)")));function Yo(t){return jo[t%jo.length]}function Uo(t){return $o[t%$o.length]}function Xo(t){let e=0;return(i,s)=>{const n=t.getDatasetMeta(s).controller;n instanceof Hn?e=function(t,e){return t.backgroundColor=t.data.map((()=>Yo(e++))),e}(i,e):n instanceof jn?e=function(t,e){return t.backgroundColor=t.data.map((()=>Uo(e++))),e}(i,e):n&&(e=function(t,e){return t.borderColor=Yo(e),t.backgroundColor=Uo(e),++e}(i,e))}}function qo(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return!0;return!1}var Ko={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(!i.enabled)return;const{data:{datasets:s},options:n}=t.config,{elements:o}=n;if(!i.forceOverride&&(qo(s)||(a=n)&&(a.borderColor||a.backgroundColor)||o&&qo(o)))return;var a;const r=Xo(t);s.forEach(r)}};function Go(t){if(t._decimated){const e=t._data;delete t._decimated,delete t._data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,writable:!0,value:e})}}function Zo(t){t.data.datasets.forEach((t=>{Go(t)}))}var Jo={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void Zo(t);const n=t.width;t.data.datasets.forEach(((e,o)=>{const{_data:a,indexAxis:r}=e,l=t.getDatasetMeta(o),h=a||e.data;if("y"===Pi([r,t.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=t.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(t.options.parsing)return;let{start:d,count:u}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=J(it(e,o.axis,a).lo,0,i-1)),s=h?J(it(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(l,h);if(u<=(i.threshold||4*n))return void Go(e);let f;switch(s(a)&&(e._data=h,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":f=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;cu&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(h,d,u,n,i);break;case"min-max":f=function(t,e,i,n){let o,a,r,l,h,c,d,u,f,g,p=0,m=0;const b=[],x=e+i-1,_=t[e].x,y=t[x].x-_;for(o=e;og&&(g=l,d=o),p=(m*p+a.x)/++m;else{const i=o-1;if(!s(c)&&!s(d)){const e=Math.min(c,d),s=Math.max(c,d);e!==u&&e!==i&&b.push({...t[e],x:p}),s!==u&&s!==i&&b.push({...t[s],x:p})}o>0&&i!==u&&b.push(t[i]),b.push(a),h=e,m=0,f=g=l,c=d=u=o}}return b}(h,d,u,n);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=f}))},destroy(t){Zo(t)}};function Qo(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=G(n),o=G(o)),{property:t,start:n,end:o}}function ta(t,e,i){for(;e>t;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function ea(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function ia(t,e){let i=[],s=!1;return n(t)?(s=!0,i=t):i=function(t,e){const{x:i=null,y:s=null}=t||{},n=e.points,o=[];return e.segments.forEach((({start:t,end:e})=>{e=ta(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new so({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function sa(t){return t&&!1!==t.fill}function na(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!a(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function oa(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=l(i&&i.target,i);void 0===s&&(s=!!e.backgroundColor);if(!1===s||null===s)return!1;if(!0===s)return"origin";return s}(t);if(o(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return a(n)&&Math.floor(n)===n?function(t,e,i,s){"-"!==t&&"+"!==t||(i=e+i);if(i===e||i<0||i>=s)return!1;return i}(s[0],e,n,i):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}function aa(t,e,i){const s=[];for(let n=0;n=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&i.fill&&ca(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;sa(i)&&ca(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;sa(s)&&"beforeDatasetDraw"===i.drawTime&&ca(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const ma=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=t.pointStyleWidth||Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class ba extends Hs{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=d(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=Si(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=ma(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,s,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const{itemWidth:p,itemHeight:m}=function(t,e,i,s,n){const o=function(t,e,i,s){let n=t.text;n&&"string"!=typeof n&&(n=n.reduce(((t,e)=>t.length>e.length?t:e)));return e+i.size/2+s.measureText(n).width}(s,t,e,i),a=function(t,e,i){let s=t;"string"!=typeof e.text&&(s=xa(e,i));return s}(n,s,e.lineHeight);return{itemWidth:o,itemHeight:a}}(i,e,n,t,s);o>0&&u+m+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:m},d=Math.max(d,p),u+=m+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:n}}=this,o=Oi(n,this.left,this.width);if(this.isHorizontal()){let n=0,a=ft(i,this.left+s,this.right-this.lineWidths[n]);for(const r of e)n!==r.row&&(n=r.row,a=ft(i,this.left+s,this.right-this.lineWidths[n])),r.top+=this.top+t+s,r.left=o.leftForLtr(o.x(a),r.width),a+=r.width+s}else{let n=0,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height);for(const r of e)r.col!==n&&(n=r.col,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height)),r.top=a,r.left+=this.left+s,r.left=o.leftForLtr(o.x(r.left),r.width),a+=r.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Ie(t,this),this._draw(),ze(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:n,labels:o}=t,a=ue.color,r=Oi(t.rtl,this.left,this.width),h=Si(o.font),{padding:c}=o,d=h.size,u=d/2;let f;this.drawTitle(),s.textAlign=r.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=h.string;const{boxWidth:g,boxHeight:p,itemHeight:m}=ma(o,d),b=this.isHorizontal(),x=this._computeTitleHeight();f=b?{x:ft(n,this.left+c,this.right-i[0]),y:this.top+c+x,line:0}:{x:this.left+c,y:ft(n,this.top+x+c,this.bottom-e[0].height),line:0},Ai(this.ctx,t.textDirection);const _=m+c;this.legendItems.forEach(((y,v)=>{s.strokeStyle=y.fontColor,s.fillStyle=y.fontColor;const M=s.measureText(y.text).width,w=r.textAlign(y.textAlign||(y.textAlign=o.textAlign)),k=g+u+M;let S=f.x,P=f.y;r.setWidth(this.width),b?v>0&&S+k+c>this.right&&(P=f.y+=_,f.line++,S=f.x=ft(n,this.left+c,this.right-i[f.line])):v>0&&P+_>this.bottom&&(S=f.x=S+e[f.line].width+c,f.line++,P=f.y=ft(n,this.top+x+c,this.bottom-e[f.line].height));if(function(t,e,i){if(isNaN(g)||g<=0||isNaN(p)||p<0)return;s.save();const n=l(i.lineWidth,1);if(s.fillStyle=l(i.fillStyle,a),s.lineCap=l(i.lineCap,"butt"),s.lineDashOffset=l(i.lineDashOffset,0),s.lineJoin=l(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=l(i.strokeStyle,a),s.setLineDash(l(i.lineDash,[])),o.usePointStyle){const a={radius:p*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},l=r.xPlus(t,g/2);Ee(s,a,l,e+u,o.pointStyleWidth&&g)}else{const o=e+Math.max((d-p)/2,0),a=r.leftForLtr(t,g),l=wi(i.borderRadius);s.beginPath(),Object.values(l).some((t=>0!==t))?He(s,{x:a,y:o,w:g,h:p,radius:l}):s.rect(a,o,g,p),s.fill(),0!==n&&s.stroke()}s.restore()}(r.x(S),P,y),S=gt(w,S+g+u,b?S+k:this.right,t.rtl),function(t,e,i){Ne(s,i.text,t,e+m/2,h,{strikethrough:i.hidden,textAlign:r.textAlign(i.textAlign)})}(r.x(S),P,y),b)f.x+=k+c;else if("string"!=typeof y.text){const t=h.lineHeight;f.y+=xa(y,t)+c}else f.y+=_})),Ti(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=Si(e.font),s=ki(e.padding);if(!e.display)return;const n=Oi(t.rtl,this.left,this.width),o=this.ctx,a=e.position,r=i.size/2,l=s.top+r;let h,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),h=this.top+l,c=ft(t.align,c,this.right-d);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);h=l+ft(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const u=ft(a,c,c+d);o.textAlign=n.textAlign(ut(a)),o.textBaseline="middle",o.strokeStyle=e.color,o.fillStyle=e.color,o.font=i.string,Ne(o,e.text,u,h,i)}_computeTitleHeight(){const t=this.options.title,e=Si(t.font),i=ki(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(tt(t,this.left,this.right)&&tt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o,useBorderRadius:a,borderRadius:r}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const l=t.controller.getStyle(i?0:void 0),h=ki(l.borderWidth);return{text:e[t.index].label,fillStyle:l.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(h.width+h.height)/4,strokeStyle:l.borderColor,pointStyle:s||l.pointStyle,rotation:l.rotation,textAlign:n||l.textAlign,borderRadius:a&&(r||l.borderRadius),datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class ya extends Hs{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=n(i.text)?i.text.length:1;this._padding=ki(i.padding);const o=s*Si(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:n,options:o}=this,a=o.align;let r,l,h,c=0;return this.isHorizontal()?(l=ft(a,i,n),h=e+t,r=n-i):("left"===o.position?(l=i+t,h=ft(a,s,e),c=-.5*C):(l=n-t,h=ft(a,e,s),c=.5*C),r=s-e),{titleX:l,titleY:h,maxWidth:r,rotation:c}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=Si(e.font),s=i.lineHeight/2+this._padding.top,{titleX:n,titleY:o,maxWidth:a,rotation:r}=this._drawArgs(s);Ne(t,e.text,0,0,i,{color:e.color,maxWidth:a,rotation:r,textAlign:ut(e.align),textBaseline:"middle",translation:[n,o]})}}var va={id:"title",_element:ya,start(t,e,i){!function(t,e){const i=new ya({ctx:t.ctx,options:e,chart:t});as.configure(t,i,e),as.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;as.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;as.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Ma=new WeakMap;var wa={id:"subtitle",start(t,e,i){const s=new ya({ctx:t.ctx,options:i,chart:t});as.configure(t,s,i),as.addBox(t,s),Ma.set(t,s)},stop(t){as.removeBox(t,Ma.get(t)),Ma.delete(t)},beforeUpdate(t,e,i){const s=Ma.get(t);as.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const ka={average(t){if(!t.length)return!1;let e,i,s=0,n=0,o=0;for(e=0,i=t.length;e-1?t.split("\n"):t}function Da(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Ca(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=Si(e.bodyFont),h=Si(e.titleFont),c=Si(e.footerFont),d=o.length,f=n.length,g=s.length,p=ki(e.padding);let m=p.height,b=0,x=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(x+=t.beforeBody.length+t.afterBody.length,d&&(m+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),x){m+=g*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(x-g)*l.lineHeight+(x-1)*e.bodySpacing}f&&(m+=e.footerMarginTop+f*c.lineHeight+(f-1)*e.footerSpacing);let _=0;const y=function(t){b=Math.max(b,i.measureText(t).width+_)};return i.save(),i.font=h.string,u(t.title,y),i.font=l.string,u(t.beforeBody.concat(t.afterBody),y),_=e.displayColors?a+2+e.boxPadding:0,u(s,(t=>{u(t.before,y),u(t.lines,y),u(t.after,y)})),_=0,i.font=c.string,u(t.footer,y),i.restore(),b+=p.width,{width:b,height:m}}function Oa(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Aa(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return it.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||Oa(t,e,i,s),yAlign:s}}function Ta(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:J(g,0,s.width-e.width),y:J(p,0,s.height-e.height)}}function La(t,e,i){const s=ki(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function Ea(t){return Sa([],Pa(t))}function Ra(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}const Ia={beforeTitle:e,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex{const e={before:[],lines:[],after:[]},n=Ra(i,t);Sa(e.before,Pa(za(n,"beforeLabel",this,t))),Sa(e.lines,za(n,"label",this,t)),Sa(e.after,Pa(za(n,"afterLabel",this,t))),s.push(e)})),s}getAfterBody(t,e){return Ea(za(e.callbacks,"afterBody",this,t))}getFooter(t,e){const{callbacks:i}=e,s=za(i,"beforeFooter",this,t),n=za(i,"footer",this,t),o=za(i,"afterFooter",this,t);let a=[];return a=Sa(a,Pa(s)),a=Sa(a,Pa(n)),a=Sa(a,Pa(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;at.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),u(l,(e=>{const i=Ra(t.callbacks,e);s.push(za(i,"labelColor",this,e)),n.push(za(i,"labelPointStyle",this,e)),o.push(za(i,"labelTextColor",this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=ka[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Ca(this,i),a=Object.assign({},t,e),r=Aa(this.chart,i,a),l=Ta(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=wi(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,b,x,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,x=_+o,y=_-o):(p=d+f,m=p+o,x=_-o,y=_+o),b=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(x=u,_=x-o,p=m-o,b=m+o):(x=u+g,_=x+o,p=m+o,b=m-o),y=x),{x1:p,x2:m,x3:b,y1:x,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Oi(i.rtl,this.x,this.width);for(t.x=La(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=Si(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,He(t,{x:e,y:g,w:h,h:l,radius:r}),t.fill(),t.stroke(),t.fillStyle=a.backgroundColor,t.beginPath(),He(t,{x:i,y:g+1,w:h-2,h:l-2,radius:r}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,h,l),t.strokeRect(e,g,h,l),t.fillStyle=a.backgroundColor,t.fillRect(i,g+1,h-2,l-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=Si(i.bodyFont);let d=c.lineHeight,f=0;const g=Oi(i.rtl,this.x,this.width),p=function(i){e.fillText(i,g.x(t.x+f),t.y+d/2),t.y+=d+n},m=g.textAlign(o);let b,x,_,y,v,M,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=La(this,m,i),e.fillStyle=i.bodyColor,u(this.beforeBody,p),f=a&&"right"!==m?"center"===o?l/2+h:l+2+h:0,y=0,M=s.length;y0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=ka[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Ca(this,t),a=Object.assign({},i,this._size),r=Aa(e,t,a),l=Ta(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=ki(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ai(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),Ti(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!f(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!f(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e;const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=ka[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}var Va={id:"tooltip",_element:Fa,positioners:ka,afterInit(t,e,i){i&&(t.tooltip=new Fa({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;if(e&&e._willRender()){const i={tooltip:e};if(!1===t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0}))return;e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)}},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:Ia},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return On.register($n,Ho,uo,t),On.helpers={...Wi},On._adapters=En,On.Animation=Cs,On.Animations=Os,On.animator=xt,On.controllers=en.controllers.items,On.DatasetController=Ns,On.Element=Hs,On.elements=uo,On.Interaction=Xi,On.layouts=as,On.platforms=Ss,On.Scale=Js,On.Ticks=ae,Object.assign(On,$n,Ho,uo,t,Ss),On.Chart=On,"undefined"!=typeof window&&(window.Chart=On),On})); +//# sourceMappingURL=chart.umd.js.map diff --git a/public/scripts/common-0.0.1-min.js b/public/scripts/common-0.0.1-min.js index 65a31cd0..5a2612d4 100644 --- a/public/scripts/common-0.0.1-min.js +++ b/public/scripts/common-0.0.1-min.js @@ -1 +1 @@ -function Q(n){return document.getElementById(n)}function QS(n){try{return Q(n).style}catch(n){}}function QE(n,t){try{Q(n).disabled=!t}catch(n){}}function QV(n,t){try{QS(n).display=t?"":"none"}catch(n){}}function QA(n,t){Q(n).innerHTML+=t}function QH(n,t){Q(n).innerHTML=t}function QC(n){try{return Q(n).classList}catch(n){}}function inputBoxFocus(n){Q(n).focus();var t=Q(n).value;Q(n).value="",Q(n).value=t}function ReadShort(n,t){return(n.charCodeAt(t)<<8)+n.charCodeAt(t+1)}function ReadShortX(n,t){return(n.charCodeAt(t+1)<<8)+n.charCodeAt(t)}function ReadInt(n,t){return 16777216*n.charCodeAt(t)+(n.charCodeAt(t+1)<<16)+(n.charCodeAt(t+2)<<8)+n.charCodeAt(t+3)}function ReadSInt(n,t){return(n.charCodeAt(t)<<24)+(n.charCodeAt(t+1)<<16)+(n.charCodeAt(t+2)<<8)+n.charCodeAt(t+3)}function ReadIntX(n,t){return 16777216*n.charCodeAt(t+3)+(n.charCodeAt(t+2)<<16)+(n.charCodeAt(t+1)<<8)+n.charCodeAt(t)}function ShortToStr(n){return String.fromCharCode(n>>8&255,255&n)}function ShortToStrX(n){return String.fromCharCode(255&n,n>>8&255)}function IntToStr(n){return String.fromCharCode(n>>24&255,n>>16&255,n>>8&255,255&n)}function IntToStrX(n){return String.fromCharCode(255&n,n>>8&255,n>>16&255,n>>24&255)}function MakeToArray(n){return n&&null!=n&&"object"!=typeof n?[n]:n}function SplitArray(n){return n.split(",")}function Clone(n){return JSON.parse(JSON.stringify(n))}function EscapeHtml(n){return"string"==typeof n?n.replace(/&/g,"&").replace(/>/g,">").replace(//g,">").replace(/").replace(/\n/g,"").replace(/\t/g,"  "):"boolean"==typeof n||"number"==typeof n?n:void 0}function ArrayElementMove(n,t,e){n.splice(e,0,n.splice(t,1)[0])}function ObjectToStringEx(n,t){var e="";if(0!=n&&(!n||null==n))return"(Null)";if(n instanceof Array)for(var r in n)e+="
"+gap(t)+"Item #"+r+": "+ObjectToStringEx(n[r],t+1);else if(n instanceof Object)for(var r in n)e+="
"+gap(t)+r+" = "+ObjectToStringEx(n[r],t+1);else e+=EscapeHtml(n);return e}function ObjectToStringEx2(n,t){var e="";if(0!=n&&(!n||null==n))return"(Null)";if(n instanceof Array)for(var r in n)e+="\r\n"+gap2(t)+"Item #"+r+": "+ObjectToStringEx2(n[r],t+1);else if(n instanceof Object)for(var r in n)e+="\r\n"+gap2(t)+r+" = "+ObjectToStringEx2(n[r],t+1);else e+=EscapeHtml(n);return e}function gap(n){for(var t="",e=0;e<4*n;e++)t+=" ";return t}function gap2(n){for(var t="",e=0;e<4*n;e++)t+=" ";return t}function ObjectToString(n){return ObjectToStringEx(n,0)}function ObjectToString2(n){return ObjectToStringEx2(n,0)}function hex2rstr(n){if("string"!=typeof n||0==n.length)return"";for(var t,e="",r=(""+n).match(/../g);t=r.shift();)e+=String.fromCharCode("0x"+t);return e}function char2hex(n){return(n+256).toString(16).substr(-2).toUpperCase()}function rstr2hex(n){for(var t="",e=0;e")&&-1==n.indexOf("&")&&-1==n.indexOf('"')&&-1==n.indexOf("'")&&-1==n.indexOf("+")&&-1==n.indexOf("(")&&-1==n.indexOf(")")&&-1==n.indexOf("#")&&-1==n.indexOf("%")&&-1==n.indexOf(":")}function isSafeString2(n){return"string"==typeof n&&-1==n.indexOf("<")&&-1==n.indexOf(">")&&-1==n.indexOf("&")&&-1==n.indexOf('"')&&-1==n.indexOf("'")&&-1==n.indexOf("+")&&-1==n.indexOf("(")&&-1==n.indexOf(")")&&-1==n.indexOf("#")&&-1==n.indexOf("%")}function parseUriArgs(n){var t,e=window.document.location.href,r={},o=(e=e.endsWith("#")?e.substring(0,e.length-1):e).split(/[\?&|]/);for(t in o.splice(0,1),o){var i,a=o[t],c=a.indexOf("=");r[i=a.substring(0,c)]=a.substring(c+1),n&&(r[i]=decodeURIComponent(a.substring(c+1))),isSafeString(r[i])?(a=parseInt(r[i]))==r[i]&&(r[i]=a):delete r[i]}return r}function check_webp_feature(t,e){var r=new Image;r.onload=function(){var n=0>8&255,255&n)}function ShortToStrX(n){return String.fromCharCode(255&n,n>>8&255)}function IntToStr(n){return String.fromCharCode(n>>24&255,n>>16&255,n>>8&255,255&n)}function IntToStrX(n){return String.fromCharCode(255&n,n>>8&255,n>>16&255,n>>24&255)}function MakeToArray(n){return n&&null!=n&&"object"!=typeof n?[n]:n}function SplitArray(n){return n.split(",")}function Clone(n){return JSON.parse(JSON.stringify(n))}function EscapeHtml(n){return"string"==typeof n?n.replace(/&/g,"&").replace(/>/g,">").replace(//g,">").replace(/").replace(/\n/g,"").replace(/\t/g,"  "):"boolean"==typeof n||"number"==typeof n?n:void 0}function ArrayElementMove(n,t,e){n.splice(e,0,n.splice(t,1)[0])}function ObjectToStringEx(n,t){var e="";if(0!=n&&(!n||null==n))return"(Null)";if(n instanceof Array)for(var r in n)e+="
"+gap(t)+"Item #"+r+": "+ObjectToStringEx(n[r],t+1);else if(n instanceof Object)for(var r in n)e+="
"+gap(t)+r+" = "+ObjectToStringEx(n[r],t+1);else e+=EscapeHtml(n);return e}function ObjectToStringEx2(n,t){var e="";if(0!=n&&(!n||null==n))return"(Null)";if(n instanceof Array)for(var r in n)e+="\r\n"+gap2(t)+"Item #"+r+": "+ObjectToStringEx2(n[r],t+1);else if(n instanceof Object)for(var r in n)e+="\r\n"+gap2(t)+r+" = "+ObjectToStringEx2(n[r],t+1);else e+=EscapeHtml(n);return e}function gap(n){for(var t="",e=0;e<4*n;e++)t+=" ";return t}function gap2(n){for(var t="",e=0;e<4*n;e++)t+=" ";return t}function ObjectToString(n){return ObjectToStringEx(n,0)}function ObjectToString2(n){return ObjectToStringEx2(n,0)}function hex2rstr(n){if("string"!=typeof n||0==n.length)return"";for(var t,e="",r=(""+n).match(/../g);t=r.shift();)e+=String.fromCharCode("0x"+t);return e}function char2hex(n){return(n+256).toString(16).substr(-2).toUpperCase()}function rstr2hex(n){for(var t="",e=0;e")&&-1==n.indexOf("&")&&-1==n.indexOf('"')&&-1==n.indexOf("'")&&-1==n.indexOf("+")&&-1==n.indexOf("(")&&-1==n.indexOf(")")&&-1==n.indexOf("#")&&-1==n.indexOf("%")&&-1==n.indexOf(":")}function isSafeString2(n){return"string"==typeof n&&-1==n.indexOf("<")&&-1==n.indexOf(">")&&-1==n.indexOf("&")&&-1==n.indexOf('"')&&-1==n.indexOf("'")&&-1==n.indexOf("+")&&-1==n.indexOf("(")&&-1==n.indexOf(")")&&-1==n.indexOf("#")&&-1==n.indexOf("%")}function parseUriArgs(n){var t,e=window.document.location.href,r={},o=(e=e.endsWith("#")?e.substring(0,e.length-1):e).split(/[\?&|]/);for(t in o.splice(0,1),o){var i,a=o[t],c=a.indexOf("=");r[i=a.substring(0,c)]=a.substring(c+1),n&&(r[i]=decodeURIComponent(a.substring(c+1))),isSafeString2(r[i])?(a=parseInt(r[i]))==r[i]&&(r[i]=a):delete r[i]}return r}function check_webp_feature(t,e){var r=new Image;r.onload=function(){var n=0{try{return!0}catch(c){return!1}})();function i(c){return new Proxy(c,{get(c,l){return l in c?c[l]:c[e]}})}const o={...t};o[e]={...t[e],...L,...M};i(o);const n={classic:{solid:"fas",regular:"far",light:"fal",thin:"fat",duotone:"fad",brands:"fab"},sharp:{solid:"fass",regular:"fasr",light:"fasl",thin:"fast"},"sharp-duotone":{solid:"fasds"}};n[e]={...n[e],...r,...m};m=i(n);const f={classic:{fab:"fa-brands",fad:"fa-duotone",fal:"fa-light",far:"fa-regular",fas:"fa-solid",fat:"fa-thin"},sharp:{fass:"fa-solid",fasr:"fa-regular",fasl:"fa-light",fast:"fa-thin"},"sharp-duotone":{fasds:"fa-solid"}};f[e]={...f[e],fak:"fa-kit"};i(f);const h={classic:{"fa-brands":"fab","fa-duotone":"fad","fa-light":"fal","fa-regular":"far","fa-solid":"fas","fa-thin":"fat"},sharp:{"fa-solid":"fass","fa-regular":"fasr","fa-light":"fasl","fa-thin":"fast"},"sharp-duotone":{"fa-solid":"fasds"}};h[e]={...h[e],"fa-kit":"fak"};i(h),i({classic:{900:"fas",400:"far",normal:"far",300:"fal",100:"fat"},sharp:{900:"fass",400:"fasr",300:"fasl",100:"fast"},"sharp-duotone":{900:"fasds"}});const d=new Set;Object.keys(m[e]).map(d.add.bind(d)),Object.keys(m.sharp).map(d.add.bind(d)),Object.keys(m["sharp-duotone"]).map(d.add.bind(d));const u=z||{};u[a]||(u[a]={}),u[a].styles||(u[a].styles={}),u[a].hooks||(u[a].hooks={}),u[a].shims||(u[a].shims=[]);var v=u[a];function p(z){return Object.keys(z).reduce((c,l)=>{var s=z[l];return!!s.icon?c[s.iconName]=s.icon:c[l]=s,c},{})}function g(c,l,s){var{skipHooks:z=!1}=2{g("fab",b),g("fa-brands",b)})}(),function(){"use strict";let c={},l={};try{"undefined"!=typeof window&&(c=window),"undefined"!=typeof document&&(l=document)}catch(c){}const{userAgent:s=""}=c.navigator||{};var z=c,a=l,e=(z.document,!a.documentElement||!a.head||"function"!=typeof a.addEventListener||a.createElement,~s.indexOf("MSIE")||s.indexOf("Trident/"),"classic"),L={fak:"kit","fa-kit":"kit"},M={fakd:"kit-duotone","fa-kit-duotone":"kit-duotone"},t={classic:{fa:"solid",fas:"solid","fa-solid":"solid",far:"regular","fa-regular":"regular",fal:"light","fa-light":"light",fat:"thin","fa-thin":"thin",fad:"duotone","fa-duotone":"duotone",fab:"brands","fa-brands":"brands"},sharp:{fa:"solid",fass:"solid","fa-solid":"solid",fasr:"regular","fa-regular":"regular",fasl:"light","fa-light":"light",fast:"thin","fa-thin":"thin"},"sharp-duotone":{fa:"solid",fasds:"solid","fa-solid":"solid"}},r={kit:"fak"},m={"kit-duotone":"fakd"},a="___FONT_AWESOME___";const C=(()=>{try{return!0}catch(c){return!1}})();function i(c){return new Proxy(c,{get(c,l){return l in c?c[l]:c[e]}})}const o={...t};o[e]={...t[e],...L,...M};i(o);const n={classic:{solid:"fas",regular:"far",light:"fal",thin:"fat",duotone:"fad",brands:"fab"},sharp:{solid:"fass",regular:"fasr",light:"fasl",thin:"fast"},"sharp-duotone":{solid:"fasds"}};n[e]={...n[e],...r,...m};m=i(n);const f={classic:{fab:"fa-brands",fad:"fa-duotone",fal:"fa-light",far:"fa-regular",fas:"fa-solid",fat:"fa-thin"},sharp:{fass:"fa-solid",fasr:"fa-regular",fasl:"fa-light",fast:"fa-thin"},"sharp-duotone":{fasds:"fa-solid"}};f[e]={...f[e],fak:"fa-kit"};i(f);const h={classic:{"fa-brands":"fab","fa-duotone":"fad","fa-light":"fal","fa-regular":"far","fa-solid":"fas","fa-thin":"fat"},sharp:{"fa-solid":"fass","fa-regular":"fasr","fa-light":"fasl","fa-thin":"fast"},"sharp-duotone":{"fa-solid":"fasds"}};h[e]={...h[e],"fa-kit":"fak"};i(h),i({classic:{900:"fas",400:"far",normal:"far",300:"fal",100:"fat"},sharp:{900:"fass",400:"fasr",300:"fasl",100:"fast"},"sharp-duotone":{900:"fasds"}});const d=new Set;Object.keys(m[e]).map(d.add.bind(d)),Object.keys(m.sharp).map(d.add.bind(d)),Object.keys(m["sharp-duotone"]).map(d.add.bind(d));const u=z||{};u[a]||(u[a]={}),u[a].styles||(u[a].styles={}),u[a].hooks||(u[a].hooks={}),u[a].shims||(u[a].shims=[]);var v=u[a];function p(z){return Object.keys(z).reduce((c,l)=>{var s=z[l];return!!s.icon?c[s.iconName]=s.icon:c[l]=s,c},{})}function g(c,l,s){var{skipHooks:z=!1}=2{g("far",b),g("fa-regular",b)})}(),function(){"use strict";let c={},l={};try{"undefined"!=typeof window&&(c=window),"undefined"!=typeof document&&(l=document)}catch(c){}const{userAgent:s=""}=c.navigator||{};var z=c,a=l,e=(z.document,!a.documentElement||!a.head||"function"!=typeof a.addEventListener||a.createElement,~s.indexOf("MSIE")||s.indexOf("Trident/"),"classic"),L={fak:"kit","fa-kit":"kit"},M={fakd:"kit-duotone","fa-kit-duotone":"kit-duotone"},t={classic:{fa:"solid",fas:"solid","fa-solid":"solid",far:"regular","fa-regular":"regular",fal:"light","fa-light":"light",fat:"thin","fa-thin":"thin",fad:"duotone","fa-duotone":"duotone",fab:"brands","fa-brands":"brands"},sharp:{fa:"solid",fass:"solid","fa-solid":"solid",fasr:"regular","fa-regular":"regular",fasl:"light","fa-light":"light",fast:"thin","fa-thin":"thin"},"sharp-duotone":{fa:"solid",fasds:"solid","fa-solid":"solid"}},r={kit:"fak"},m={"kit-duotone":"fakd"},a="___FONT_AWESOME___";const C=(()=>{try{return!0}catch(c){return!1}})();function i(c){return new Proxy(c,{get(c,l){return l in c?c[l]:c[e]}})}const o={...t};o[e]={...t[e],...L,...M};i(o);const n={classic:{solid:"fas",regular:"far",light:"fal",thin:"fat",duotone:"fad",brands:"fab"},sharp:{solid:"fass",regular:"fasr",light:"fasl",thin:"fast"},"sharp-duotone":{solid:"fasds"}};n[e]={...n[e],...r,...m};m=i(n);const f={classic:{fab:"fa-brands",fad:"fa-duotone",fal:"fa-light",far:"fa-regular",fas:"fa-solid",fat:"fa-thin"},sharp:{fass:"fa-solid",fasr:"fa-regular",fasl:"fa-light",fast:"fa-thin"},"sharp-duotone":{fasds:"fa-solid"}};f[e]={...f[e],fak:"fa-kit"};i(f);const h={classic:{"fa-brands":"fab","fa-duotone":"fad","fa-light":"fal","fa-regular":"far","fa-solid":"fas","fa-thin":"fat"},sharp:{"fa-solid":"fass","fa-regular":"fasr","fa-light":"fasl","fa-thin":"fast"},"sharp-duotone":{"fa-solid":"fasds"}};h[e]={...h[e],"fa-kit":"fak"};i(h),i({classic:{900:"fas",400:"far",normal:"far",300:"fal",100:"fat"},sharp:{900:"fass",400:"fasr",300:"fasl",100:"fast"},"sharp-duotone":{900:"fasds"}});const d=new Set;Object.keys(m[e]).map(d.add.bind(d)),Object.keys(m.sharp).map(d.add.bind(d)),Object.keys(m["sharp-duotone"]).map(d.add.bind(d));const u=z||{};u[a]||(u[a]={}),u[a].styles||(u[a].styles={}),u[a].hooks||(u[a].hooks={}),u[a].shims||(u[a].shims=[]);var v=u[a];function p(z){return Object.keys(z).reduce((c,l)=>{var s=z[l];return!!s.icon?c[s.iconName]=s.icon:c[l]=s,c},{})}function g(c,l,s){var{skipHooks:z=!1}=2{g("fas",b),g("fa-solid",b)})}(),function(){"use strict";var c=()=>{};let l={},s={},z=null,a={mark:c,measure:c};try{"undefined"!=typeof window&&(l=window),"undefined"!=typeof document&&(s=document),"undefined"!=typeof MutationObserver&&(z=MutationObserver),"undefined"!=typeof performance&&(a=performance)}catch(c){}const{userAgent:e=""}=l.navigator||{},g=l,b=s,t=z;var L=a;const M=!!g.document,m=!!b.documentElement&&!!b.head&&"function"==typeof b.addEventListener&&"function"==typeof b.createElement,C=~e.indexOf("MSIE")||~e.indexOf("Trident/");var r="classic",i="duotone",o="sharp",n="sharp-duotone",f=[r,i,o,n],h={fak:"kit","fa-kit":"kit"},d={fakd:"kit-duotone","fa-kit-duotone":"kit-duotone"},u={classic:{fa:"solid",fas:"solid","fa-solid":"solid",far:"regular","fa-regular":"regular",fal:"light","fa-light":"light",fat:"thin","fa-thin":"thin",fad:"duotone","fa-duotone":"duotone",fab:"brands","fa-brands":"brands"},sharp:{fa:"solid",fass:"solid","fa-solid":"solid",fasr:"regular","fa-regular":"regular",fasl:"light","fa-light":"light",fast:"thin","fa-thin":"thin"},"sharp-duotone":{fa:"solid",fasds:"solid","fa-solid":"solid"}},v=[1,2,3,4,5,6,7,8,9,10],p=v.concat([11,12,13,14,15,16,17,18,19,20]),H={GROUP:"duotone-group",SWAP_OPACITY:"swap-opacity",PRIMARY:"primary",SECONDARY:"secondary"},V=[...Object.keys({classic:["fas","far","fal","fat"],sharp:["fass","fasr","fasl","fast"],"sharp-duotone":["fasds"]}),"solid","regular","light","thin","duotone","brands","2xs","xs","sm","lg","xl","2xl","beat","border","fade","beat-fade","bounce","flip-both","flip-horizontal","flip-vertical","flip","fw","inverse","layers-counter","layers-text","layers","li","pull-left","pull-right","pulse","rotate-180","rotate-270","rotate-90","rotate-by","shake","spin-pulse","spin-reverse","spin","stack-1x","stack-2x","stack","ul",H.GROUP,H.SWAP_OPACITY,H.PRIMARY,H.SECONDARY].concat(v.map(c=>"".concat(c,"x"))).concat(p.map(c=>"w-".concat(c))),c={kit:"fak"},v={"kit-duotone":"fakd"},p="___FONT_AWESOME___";const k=16,w="svg-inline--fa",y="data-fa-i2svg",A="data-fa-pseudo-element",S="data-fa-pseudo-element-pending",x="data-prefix",q="data-icon",Z="fontawesome-i2svg",j="async",O=["HTML","HEAD","STYLE","SCRIPT"],N=(()=>{try{return!0}catch(c){return!1}})(),P=[r,o,n];function E(c){return new Proxy(c,{get(c,l){return l in c?c[l]:c[r]}})}const F={...u};F[r]={...u[r],...h,...d};const I=E(F),T={classic:{solid:"fas",regular:"far",light:"fal",thin:"fat",duotone:"fad",brands:"fab"},sharp:{solid:"fass",regular:"fasr",light:"fasl",thin:"fast"},"sharp-duotone":{solid:"fasds"}};T[r]={...T[r],...c,...v};const R=E(T),D={classic:{fab:"fa-brands",fad:"fa-duotone",fal:"fa-light",far:"fa-regular",fas:"fa-solid",fat:"fa-thin"},sharp:{fass:"fa-solid",fasr:"fa-regular",fasl:"fa-light",fast:"fa-thin"},"sharp-duotone":{fasds:"fa-solid"}};D[r]={...D[r],fak:"fa-kit"};const _=E(D),Y={classic:{"fa-brands":"fab","fa-duotone":"fad","fa-light":"fal","fa-regular":"far","fa-solid":"fas","fa-thin":"fat"},sharp:{"fa-solid":"fass","fa-regular":"fasr","fa-light":"fasl","fa-thin":"fast"},"sharp-duotone":{"fa-solid":"fasds"}};Y[r]={...Y[r],"fa-kit":"fak"};const W=E(Y),B=/fa(s|r|l|t|d|b|k|kd|ss|sr|sl|st|sds)?[\-\ ]/,U="fa-layers-text",X=/Font ?Awesome ?([56 ]*)(Solid|Regular|Light|Thin|Duotone|Brands|Free|Pro|Sharp Duotone|Sharp|Kit)?.*/i;E({classic:{900:"fas",400:"far",normal:"far",300:"fal",100:"fat"},sharp:{900:"fass",400:"fasr",300:"fasl",100:"fast"},"sharp-duotone":{900:"fasds"}});const G=["class","data-prefix","data-icon","data-fa-transform","data-fa-mask"],Q=H,K=new Set;Object.keys(R[r]).map(K.add.bind(K)),Object.keys(R[o]).map(K.add.bind(K)),Object.keys(R[n]).map(K.add.bind(K));const J=["kit",...V],$=g.FontAwesomeConfig||{};if(b&&"function"==typeof b.querySelector){const U2=[["data-family-prefix","familyPrefix"],["data-css-prefix","cssPrefix"],["data-family-default","familyDefault"],["data-style-default","styleDefault"],["data-replacement-class","replacementClass"],["data-auto-replace-svg","autoReplaceSvg"],["data-auto-add-css","autoAddCss"],["data-auto-a11y","autoA11y"],["data-search-pseudo-elements","searchPseudoElements"],["data-observe-mutations","observeMutations"],["data-mutate-approach","mutateApproach"],["data-keep-original-source","keepOriginalSource"],["data-measure-performance","measurePerformance"],["data-show-missing-icons","showMissingIcons"]];U2.forEach(c=>{var[l,c]=c,l=""===(l=function(c){var l=b.querySelector("script["+c+"]");if(l)return l.getAttribute(c)}(l))||"false"!==l&&("true"===l||l);null!=l&&($[c]=l)})}v={styleDefault:"solid",familyDefault:"classic",cssPrefix:"fa",replacementClass:w,autoReplaceSvg:!0,autoAddCss:!0,autoA11y:!0,searchPseudoElements:!1,observeMutations:!0,mutateApproach:"async",keepOriginalSource:!0,measurePerformance:!1,showMissingIcons:!0};$.familyPrefix&&($.cssPrefix=$.familyPrefix);const c1={...v,...$};c1.autoReplaceSvg||(c1.observeMutations=!1);const l1={};Object.keys(v).forEach(l=>{Object.defineProperty(l1,l,{enumerable:!0,set:function(c){c1[l]=c,s1.forEach(c=>c(l1))},get:function(){return c1[l]}})}),Object.defineProperty(l1,"familyPrefix",{enumerable:!0,set:function(c){c1.cssPrefix=c,s1.forEach(c=>c(l1))},get:function(){return c1.cssPrefix}}),g.FontAwesomeConfig=l1;const s1=[];const z1=k,a1={size:16,x:0,y:0,rotate:0,flipX:!1,flipY:!1};const e1="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";function L1(){let c=12,l="";for(;0>>0;c--;)s[c]=l[c];return s}function t1(c){return c.classList?M1(c.classList):(c.getAttribute("class")||"").split(" ").filter(c=>c)}function r1(c){return"".concat(c).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function m1(s){return Object.keys(s||{}).reduce((c,l)=>c+"".concat(l,": ").concat(s[l].trim(),";"),"")}function C1(c){return c.size!==a1.size||c.x!==a1.x||c.y!==a1.y||c.rotate!==a1.rotate||c.flipX||c.flipY}function i1(){var c,l,s=w,z=l1.cssPrefix,a=l1.replacementClass;let e=':host,:root{--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free";--fa-font-light:normal 300 1em/1 "Font Awesome 6 Pro";--fa-font-thin:normal 100 1em/1 "Font Awesome 6 Pro";--fa-font-duotone:normal 900 1em/1 "Font Awesome 6 Duotone";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands";--fa-font-sharp-solid:normal 900 1em/1 "Font Awesome 6 Sharp";--fa-font-sharp-regular:normal 400 1em/1 "Font Awesome 6 Sharp";--fa-font-sharp-light:normal 300 1em/1 "Font Awesome 6 Sharp";--fa-font-sharp-thin:normal 100 1em/1 "Font Awesome 6 Sharp";--fa-font-sharp-duotone-solid:normal 900 1em/1 "Font Awesome 6 Sharp Duotone"}svg:not(:host).svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible;box-sizing:content-box}.svg-inline--fa{display:var(--fa-display,inline-block);height:1em;overflow:visible;vertical-align:-.125em}.svg-inline--fa.fa-2xs{vertical-align:.1em}.svg-inline--fa.fa-xs{vertical-align:0}.svg-inline--fa.fa-sm{vertical-align:-.0714285705em}.svg-inline--fa.fa-lg{vertical-align:-.2em}.svg-inline--fa.fa-xl{vertical-align:-.25em}.svg-inline--fa.fa-2xl{vertical-align:-.3125em}.svg-inline--fa.fa-pull-left{margin-right:var(--fa-pull-margin,.3em);width:auto}.svg-inline--fa.fa-pull-right{margin-left:var(--fa-pull-margin,.3em);width:auto}.svg-inline--fa.fa-li{width:var(--fa-li-width,2em);top:.25em}.svg-inline--fa.fa-fw{width:var(--fa-fw-width,1.25em)}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{transform-origin:center center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:var(--fa-counter-background-color,#ff253a);border-radius:var(--fa-counter-border-radius,1em);box-sizing:border-box;color:var(--fa-inverse,#fff);line-height:var(--fa-counter-line-height,1);max-width:var(--fa-counter-max-width,5em);min-width:var(--fa-counter-min-width,1.5em);overflow:hidden;padding:var(--fa-counter-padding,.25em .5em);right:var(--fa-right,0);text-overflow:ellipsis;top:var(--fa-top,0);transform:scale(var(--fa-counter-scale,.25));transform-origin:top right}.fa-layers-bottom-right{bottom:var(--fa-bottom,0);right:var(--fa-right,0);top:auto;transform:scale(var(--fa-layers-scale,.25));transform-origin:bottom right}.fa-layers-bottom-left{bottom:var(--fa-bottom,0);left:var(--fa-left,0);right:auto;top:auto;transform:scale(var(--fa-layers-scale,.25));transform-origin:bottom left}.fa-layers-top-right{top:var(--fa-top,0);right:var(--fa-right,0);transform:scale(var(--fa-layers-scale,.25));transform-origin:top right}.fa-layers-top-left{left:var(--fa-left,0);right:auto;top:var(--fa-top,0);transform:scale(var(--fa-layers-scale,.25));transform-origin:top left}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.0833333337em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.0714285718em;vertical-align:.0535714295em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.0416666682em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(-1 * var(--fa-li-width,2em));position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-color:var(--fa-border-color,#eee);border-radius:var(--fa-border-radius,.1em);border-style:var(--fa-border-style,solid);border-width:var(--fa-border-width,.08em);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{animation-name:fa-beat;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{animation-name:fa-bounce;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{animation-name:fa-fade;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade{animation-name:fa-beat-fade;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{animation-name:fa-flip;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{animation-name:fa-shake;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin{animation-name:fa-spin;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,2s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{animation-name:fa-spin;animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{animation-delay:-1ms;animation-duration:1ms;animation-iteration-count:1;transition-delay:0s;transition-duration:0s}}@keyframes fa-beat{0%,90%{transform:scale(1)}45%{transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-bounce{0%{transform:scale(1,1) translateY(0)}10%{transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{transform:scale(1,1) translateY(var(--fa-bounce-rebound,-.125em))}64%{transform:scale(1,1) translateY(0)}100%{transform:scale(1,1) translateY(0)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-beat-fade{0%,100%{opacity:var(--fa-beat-fade-opacity,.4);transform:scale(1)}50%{opacity:1;transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-flip{50%{transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-shake{0%{transform:rotate(-15deg)}4%{transform:rotate(15deg)}24%,8%{transform:rotate(-18deg)}12%,28%{transform:rotate(18deg)}16%{transform:rotate(-22deg)}20%{transform:rotate(22deg)}32%{transform:rotate(-12deg)}36%{transform:rotate(12deg)}100%,40%{transform:rotate(0)}}@keyframes fa-spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.fa-rotate-90{transform:rotate(90deg)}.fa-rotate-180{transform:rotate(180deg)}.fa-rotate-270{transform:rotate(270deg)}.fa-flip-horizontal{transform:scale(-1,1)}.fa-flip-vertical{transform:scale(1,-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1,-1)}.fa-rotate-by{transform:rotate(var(--fa-rotate-angle,0))}.fa-stack{display:inline-block;vertical-align:middle;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0;z-index:var(--fa-stack-z-index,auto)}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:var(--fa-inverse,#fff)}.fa-sr-only,.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.fa-sr-only-focusable:not(:focus),.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor);opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fa-duotone.fa-inverse,.fad.fa-inverse{color:var(--fa-inverse,#fff)}';return"fa"===z&&a===s||(c=new RegExp("\\.".concat("fa","\\-"),"g"),l=new RegExp("\\--".concat("fa","\\-"),"g"),s=new RegExp("\\.".concat(s),"g"),e=e.replace(c,".".concat(z,"-")).replace(l,"--".concat(z,"-")).replace(s,".".concat(a))),e}let o1=!1;function n1(){l1.autoAddCss&&!o1&&(function(c){if(c&&m){const a=b.createElement("style");a.setAttribute("type","text/css"),a.innerHTML=c;var s=b.head.childNodes;let l=null;for(let c=s.length-1;-1c())}const u1=[];let v1=!1;function p1(c){m&&(v1?setTimeout(c,0):u1.push(c))}function g1(c){const{tag:l,attributes:s={},children:z=[]}=c;return"string"==typeof c?r1(c):"<".concat(l," ").concat((a=s,Object.keys(a||{}).reduce((c,l)=>c+"".concat(l,'="').concat(r1(a[l]),'" '),"").trim()),">").concat(z.map(g1).join(""),"");var a}function b1(c,l,s){if(c&&c[l]&&c[l][s])return{prefix:l,iconName:s,icon:c[l][s]}}m&&(v1=(b.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(b.readyState),v1||b.addEventListener("DOMContentLoaded",d1));function H1(c,l,s,z){for(var a,e,L=Object.keys(c),M=L.length,t=void 0!==z?V1(l,z):l,r=void 0===s?(a=1,c[L[0]]):(a=0,s);a{var s=z[l];return!!s.icon?c[s.iconName]=s.icon:c[l]=s,c},{})}function y1(c,l,s){var{skipHooks:z=!1}=2{var c=z=>H1(A1,(c,l,s)=>(c[s]=H1(l,z,{}),c),{});Z1=c((l,c,s)=>{if(c[3]&&(l[c[3]]=s),c[2]){const z=c[2].filter(c=>"number"==typeof c);z.forEach(c=>{l[c.toString(16)]=s})}return l}),j1=c((l,c,s)=>{if(l[s]=s,c[2]){const z=c[2].filter(c=>"string"==typeof c);z.forEach(c=>{l[c]=s})}return l}),P1=c((l,c,s)=>{const z=c[2];return l[s]=s,z.forEach(c=>{l[c]=s}),l});const a="far"in A1||l1.autoFetchSvg;c=H1(S1,(c,l)=>{const s=l[0];let z=l[1];l=l[2];return"far"!==z||a||(z="fas"),"string"==typeof s&&(c.names[s]={prefix:z,iconName:l}),"number"==typeof s&&(c.unicodes[s.toString(16)]={prefix:z,iconName:l}),c},{names:{},unicodes:{}});O1=c.names,N1=c.unicodes,q1=Y1(l1.styleDefault,{family:l1.familyDefault})};function T1(c,l){return(Z1[c]||{})[l]}function R1(c,l){return(P1[c]||{})[l]}function D1(c){return O1[c]||{prefix:null,iconName:null}}V=c=>{q1=Y1(c.styleDefault,{family:l1.familyDefault})},s1.push(V),I1();const _1=()=>({prefix:null,iconName:null,rest:[]});function Y1(c,l){var{family:s=r}=1c!==i);t.forEach(l=>{(c.includes(e[l])||c.some(c=>W1[l].includes(c)))&&(M=l)});const s=c.reduce((c,l)=>{var s,z=F1(l1.cssPrefix,l);return A1[l]?(l=x1[M].includes(l)?W[M][l]:l,L=l,c.prefix=l):-1l===e[c])||c.rest.push(l),!a&&c.prefix&&c.iconName&&(s="fa"===L?D1(c.iconName):{},z=R1(c.prefix,c.iconName),s.prefix&&(L=null),c.iconName=s.iconName||z||c.iconName,c.prefix=s.prefix||c.prefix,"far"!==c.prefix||A1.far||!A1.fas||l1.autoFetchSvg||(c.prefix="fas")),c},_1());return(c.includes("fa-brands")||c.includes("fab"))&&(s.prefix="fab"),(c.includes("fa-duotone")||c.includes("fad"))&&(s.prefix="fad"),s.prefix||M!==o||!A1.fass&&!l1.autoFetchSvg||(s.prefix="fass",s.iconName=R1(s.prefix,s.iconName)||s.iconName),s.prefix||M!==n||!A1.fasds&&!l1.autoFetchSvg||(s.prefix="fasds",s.iconName=R1(s.prefix,s.iconName)||s.iconName),"fa"!==s.prefix&&"fa"!==L||(s.prefix=q1||"fas"),s}let U1=[],X1={};const G1={},Q1=Object.keys(G1);function K1(c,l){for(var s=arguments.length,z=new Array(2{l=c.apply(null,[l,...z])}),l}function J1(c){for(var l=arguments.length,s=new Array(1{c.apply(null,s)})}function $1(c){var l=c,c=Array.prototype.slice.call(arguments,1);return G1[l]?G1[l].apply(null,c):void 0}function c2(c){"fa"===c.prefix&&(c.prefix="fas");let l=c["iconName"];c=c.prefix||q1;if(l)return l=R1(c,l)||l,b1(l2.definitions,c,l)||b1(h1.styles,c,l)}const l2=new class{constructor(){this.definitions={}}add(){for(var c=arguments.length,l=new Array(c),s=0;s{this.definitions[c]={...this.definitions[c]||{},...z[c]},y1(c,z[c]);var l=_[r][c];l&&y1(l,z[c]),I1()})}reset(){this.definitions={}}_pullDefinitions(e,c){const L=c.prefix&&c.iconName&&c.icon?{0:c}:c;return Object.keys(L).map(c=>{const{prefix:l,iconName:s,icon:z}=L[c],a=z[2];e[l]||(e[l]={}),0{"string"==typeof c&&(e[l][c]=z)}),e[l][s]=z}),e}};const s2={noAuto:()=>{l1.autoReplaceSvg=!1,l1.observeMutations=!1,J1("noAuto")},config:l1,dom:{i2svg:function(){var c=0{z2({autoReplaceSvgRoot:l}),J1("watch",c)})}},parse:{icon:c=>{if(null===c)return null;if("object"==typeof c&&c.prefix&&c.iconName)return{prefix:c.prefix,iconName:R1(c.prefix,c.iconName)||c.iconName};if(Array.isArray(c)&&2===c.length){var l=0===c[1].indexOf("fa-")?c[1].slice(3):c[1],s=Y1(c[0]);return{prefix:s,iconName:R1(s,l)||l}}if("string"==typeof c&&(-1g1(c))}}),Object.defineProperty(l,"node",{get:function(){if(m){const c=b.createElement("div");return c.innerHTML=l.html,c.children}}}),l}function e2(c){const{icons:{main:l,mask:s},prefix:z,iconName:a,transform:e,symbol:L,title:M,maskId:t,titleId:r,extra:m,watchable:C=!1}=c;var{width:i,height:o}=s.found?s:l,n="fak"===z,c=[l1.replacementClass,a?"".concat(l1.cssPrefix,"-").concat(a):""].filter(c=>-1===m.classes.indexOf(c)).filter(c=>""!==c||!!c).concat(m.classes).join(" ");let f={children:[],attributes:{...m.attributes,"data-prefix":z,"data-icon":a,class:c,role:m.attributes.role||"img",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 ".concat(i," ").concat(o)}};i=n&&!~m.classes.indexOf("fa-fw")?{width:"".concat(i/o*16*.0625,"em")}:{};C&&(f.attributes[y]=""),M&&(f.children.push({tag:"title",attributes:{id:f.attributes["aria-labelledby"]||"title-".concat(r||L1())},children:[M]}),delete f.attributes.title);const h={...f,prefix:z,iconName:a,main:l,mask:s,maskId:t,transform:e,symbol:L,styles:{...i,...m.styles}};var{children:o,attributes:i}=s.found&&l.found?$1("generateAbstractMask",h)||{children:[],attributes:{}}:$1("generateAbstractIcon",h)||{children:[],attributes:{}};return h.children=o,h.attributes=i,(L?function(c){var{prefix:l,iconName:s,children:z,attributes:a,symbol:c}=c,c=!0===c?"".concat(l,"-").concat(l1.cssPrefix,"-").concat(s):c;return[{tag:"svg",attributes:{style:"display: none;"},children:[{tag:"symbol",attributes:{...a,id:c},children:z}]}]}:function(c){let{children:l,main:s,mask:z,attributes:a,styles:e,transform:L}=c;if(C1(L)&&s.found&&!z.found){var{width:M,height:c}=s;const t=M/c/2,r=.5;a.style=m1({...e,"transform-origin":"".concat(t+L.x/16,"em ").concat(r+L.y/16,"em")})}return[{tag:"svg",attributes:a,children:l}]})(h)}function L2(c){const{content:l,width:s,height:z,transform:a,title:e,extra:L,watchable:M=!1}=c,t={...L.attributes,...e?{title:e}:{},class:L.classes.join(" ")};M&&(t[y]="");const r={...L.styles};C1(a)&&(r.transform=function(c){var{transform:l,width:s=k,height:z=k,startCentered:c=!1}=c;let a="";return c&&C?a+="translate(".concat(l.x/z1-s/2,"em, ").concat(l.y/z1-z/2,"em) "):a+=c?"translate(calc(-50% + ".concat(l.x/z1,"em), calc(-50% + ").concat(l.y/z1,"em)) "):"translate(".concat(l.x/z1,"em, ").concat(l.y/z1,"em) "),a+="scale(".concat(l.size/z1*(l.flipX?-1:1),", ").concat(l.size/z1*(l.flipY?-1:1),") "),a+="rotate(".concat(l.rotate,"deg) "),a}({transform:a,startCentered:!0,width:s,height:z}),r["-webkit-transform"]=r.transform);c=m1(r);0{var s,z;if("fa"===L&&(z=D1(a)||{},a=z.iconName||a,e=z.prefix||e),a&&e&&M2[e]&&M2[e][a])return c(t2(M2[e][a]));s=a,z=e,N||l1.showMissingIcons||!s||console.error('Icon with name "'.concat(s,'" and prefix "').concat(z,'" is missing.')),c({...r2,icon:l1.showMissingIcons&&a&&$1("missingIconAbstract")||{}})})}v=()=>{};const C2=l1.measurePerformance&&L&&L.mark&&L.measure?L:{mark:v,measure:v},i2='FA "6.6.0"';const o2=c=>{C2.mark("".concat(i2," ").concat(c," ends")),C2.measure("".concat(i2," ").concat(c),"".concat(i2," ").concat(c," begins"),"".concat(i2," ").concat(c," ends"))};var n2={begin:c=>(C2.mark("".concat(i2," ").concat(c," begins")),()=>o2(c)),end:o2};const f2=()=>{};function h2(c){return"string"==typeof(c.getAttribute?c.getAttribute(y):null)}function d2(l,c){const{ceFn:s="svg"===l.tag?function(c){return b.createElementNS("http://www.w3.org/2000/svg",c)}:function(c){return b.createElement(c)}}=1{l.parentNode.insertBefore(d2(c),l)}),null===l.getAttribute(y)&&l1.keepOriginalSource?(c=b.createComment((c=l,c=" ".concat(c.outerHTML," "),c="".concat(c,"Font Awesome fontawesome.com "))),l.parentNode.replaceChild(c,l)):l.remove())},nest:function(c){const l=c[0],s=c[1];if(~t1(l).indexOf(l1.replacementClass))return u2.replace(c);const z=new RegExp("".concat(l1.cssPrefix,"-.*"));if(delete s[0].attributes.id,s[0].attributes.class){const a=s[0].attributes.class.split(" ").reduce((c,l)=>((l===l1.replacementClass||l.match(z)?c.toSvg:c.toNode).push(l),c),{toNode:[],toSvg:[]});s[0].attributes.class=a.toSvg.join(" "),0===a.toNode.length?l.removeAttribute("class"):l.setAttribute("class",a.toNode.join(" "))}c=s.map(c=>g1(c)).join("\n");l.setAttribute(y,""),l.innerHTML=c}};function v2(c){c()}function p2(s,c){const z="function"==typeof c?c:f2;if(0===s.length)z();else{let c=v2;l1.mutateApproach===j&&(c=g.requestAnimationFrame||v2),c(()=>{var c=!0!==l1.autoReplaceSvg&&u2[l1.autoReplaceSvg]||u2.replace;const l=n2.begin("mutate");s.map(c),l(),z()})}}let g2=!1;function b2(){g2=!0}function H2(){g2=!1}let V2=null;function k2(c){if(!t)return;if(!l1.observeMutations)return;const{treeCallback:e=f2,nodeCallback:L=f2,pseudoElementsCallback:M=f2,observeMutationsRoot:l=b}=c;V2=new t(c=>{if(!g2){const a=q1;M1(c).forEach(c=>{var l,s,z;"childList"===c.type&&0("class"!==c.name&&"style"!==c.name&&(c[l.name]=l.value),c),{});var s=c.getAttribute("title"),c=c.getAttribute("data-fa-title-id");return l1.autoA11y&&(s?l["aria-labelledby"]="".concat(l1.replacementClass,"-title-").concat(c||L1()):(l["aria-hidden"]="true",l.focusable="false")),l}(c),l=K1("parseNodeAttributes",{},c),s=s.styleParser?function(c){const l=c.getAttribute("style");let s=[];return l&&(s=l.split(";").reduce((c,l)=>{const s=l.split(":");l=s[0];const z=s.slice(1);return l&&0l.add("".concat(Z,"-").concat(c)),e=c=>l.remove("".concat(Z,"-").concat(c)),s=l1.autoFetchSvg?x2:P.map(c=>"fa-".concat(c)).concat(Object.keys(A2));s.includes("fa")||s.push("fa");var L=[".".concat(U,":not([").concat(y,"])")].concat(s.map(c=>".".concat(c,":not([").concat(y,"])"))).join(", ");if(0===L.length)return Promise.resolve();let M=[];try{M=M1(c.querySelectorAll(L))}catch(c){}if(!(0{try{var s=S2(l);s&&c.push(s)}catch(c){N||"MissingIcon"===c.name&&console.error(c)}return c},[]);return new Promise((l,s)=>{Promise.all(r).then(c=>{p2(c,()=>{a("active"),a("complete"),e("pending"),"function"==typeof z&&z(),t(),l()})}).catch(c=>{t(),s(c)})})}function Z2(c){let l=1{c&&p2([c],l)})}P.map(c=>{x2.add("fa-".concat(c))}),Object.keys(I[r]).map(x2.add.bind(x2)),Object.keys(I[o]).map(x2.add.bind(x2)),Object.keys(I[n]).map(x2.add.bind(x2)),x2=[...x2];function j2(c){let l=1(J1("beforeDOMElementCreation",{iconDefinition:c,params:l}),l1.autoA11y&&(L?r["aria-labelledby"]="".concat(l1.replacementClass,"-title-").concat(M||L1()):(r["aria-hidden"]="true",r.focusable="false")),e2({icons:{main:t2(o),mask:a?t2(a.icon):{found:!1,width:null,height:null,icon:{}}},prefix:C,iconName:i,transform:{...a1,...s},symbol:z,title:L,maskId:e,titleId:M,extra:{attributes:r,styles:m,classes:t}})))}}p={mixout(){return{icon:(z=j2,function(c){var l=1{}}=c;return q2(l,c)},c.generateSvgReplacementMutation=function(z,c){const{iconName:a,title:e,titleId:L,prefix:M,transform:t,symbol:r,mask:l,maskId:m,extra:C}=c;return new Promise((s,c)=>{Promise.all([m2(a,M),l.iconName?m2(l.iconName,l.prefix):Promise.resolve({found:!1,width:512,height:512,icon:{}})]).then(c=>{var[l,c]=c;s([z,e2({icons:{main:l,mask:c},prefix:M,iconName:a,transform:t,symbol:r,maskId:m,title:e,titleId:L,extra:C,watchable:!0})])}).catch(c)})},c.generateAbstractIcon=function(c){let{children:l,attributes:s,main:z,transform:a,styles:e}=c;c=m1(e);0{J1("beforeDOMElementCreation",{assembler:c,params:s});let l=[];return c(c=>{Array.isArray(c)?c.map(c=>{l=l.concat(c.abstract)}):l=l.concat(c.abstract)}),[{tag:"span",attributes:{class:["".concat(l1.cssPrefix,"-layers"),...z].join(" ")},children:l}]})}}}},L={mixout(){return{counter(c){let l=1(J1("beforeDOMElementCreation",{content:c,params:l}),function(c){const{content:l,title:s,extra:z}=c,a={...z.attributes,...s?{title:s}:{},class:z.classes.join(" ")};0<(c=m1(z.styles)).length&&(a.style=c);const e=[];return e.push({tag:"span",attributes:a,children:[l]}),s&&e.push({tag:"span",attributes:{class:"sr-only"},children:[s]}),e}({content:c.toString(),title:s,extra:{attributes:a,styles:e,classes:["".concat(l1.cssPrefix,"-layers-counter"),...z]}})))}}}},v={mixout(){return{text(c){let l=1(J1("beforeDOMElementCreation",{content:c,params:l}),L2({content:c,transform:{...a1,...s},title:z,extra:{attributes:e,styles:L,classes:["".concat(l1.cssPrefix,"-layers-text"),...a]}})))}}},provides(c){c.generateLayersText=function(c,l){const{title:s,transform:z,extra:a}=l;let e=null,L=null;var M;return C&&(M=parseInt(getComputedStyle(c).fontSize,10),l=c.getBoundingClientRect(),e=l.width/M,L=l.height/M),l1.autoA11y&&!s&&(a.attributes["aria-hidden"]="true"),Promise.resolve([c,L2({content:c.innerHTML,width:e,height:L,transform:z,title:s,extra:a,watchable:!0})])}}};const O2=new RegExp('"',"ug"),N2=[1105920,1112319],P2={FontAwesome:{normal:"fas",400:"fas"},"Font Awesome 6 Free":{900:"fas",400:"far"},"Font Awesome 6 Pro":{900:"fas",400:"far",normal:"far",300:"fal",100:"fat"},"Font Awesome 6 Brands":{400:"fab",normal:"fab"},"Font Awesome 6 Duotone":{900:"fad"},"Font Awesome 6 Sharp":{900:"fass",400:"fasr",normal:"fasr",300:"fasl",100:"fast"},"Font Awesome 6 Sharp Duotone":{900:"fasds"},"Font Awesome 5 Free":{900:"fas",400:"far"},"Font Awesome 5 Pro":{900:"fas",400:"far",normal:"far",300:"fal"},"Font Awesome 5 Brands":{400:"fab",normal:"fab"},"Font Awesome 5 Duotone":{900:"fad"},"Font Awesome Kit":{400:"fak",normal:"fak"},"Font Awesome Kit Duotone":{400:"fakd",normal:"fakd"}},E2=Object.keys(P2).reduce((c,l)=>(c[l.toLowerCase()]=P2[l],c),{}),F2=Object.keys(E2).reduce((c,l)=>{var s=E2[l];return c[l]=s[900]||[...Object.entries(s)][0][1],c},{});function I2(u,v){const p="".concat(S).concat(v.replace(":","-"));return new Promise((e,l)=>{if(null!==u.getAttribute(p))return e();const c=M1(u.children),s=c.filter(c=>c.getAttribute(A)===v)[0],L=g.getComputedStyle(u,v),M=L.getPropertyValue("font-family"),t=M.match(X);var r,m,C=L.getPropertyValue("font-weight");const i=L.getPropertyValue("content");if(s&&!t)return u.removeChild(s),e();if(t&&"none"!==i&&""!==i){const i=L.getPropertyValue("content");let z=(r=M,m=C,r=r.replace(/^['"]|['"]$/g,"").toLowerCase(),m=parseInt(m),m=isNaN(m)?"normal":m,(E2[r]||{})[m]||F2[r]);var{value:o,isSecondary:n}=(f=i,o=f.replace(O2,""),C=0,r=(m=o).length,f=(n=55296<=(f=m.charCodeAt(C))&&f<=56319&&C+1=N2[0]&&n<=N2[1],{value:k1((n=2===o.length&&o[0]===o[1])?o[0]:o),isSecondary:f||n}),f=t[0].startsWith("FontAwesome");let c=T1(z,o),a=c;if(f&&(f=o,o=N1[f],f=T1("fas",f),(f=o||(f?{prefix:"fas",iconName:f}:null)||{prefix:null,iconName:null}).iconName&&f.prefix&&(c=f.iconName,z=f.prefix)),!c||n||s&&s.getAttribute(x)===z&&s.getAttribute(q)===a)e();else{u.setAttribute(p,a),s&&u.removeChild(s);const h={iconName:null,title:null,titleId:null,prefix:null,transform:a1,symbol:!1,mask:{iconName:null,prefix:null,rest:[]},maskId:null,extra:{classes:[],styles:{},attributes:{}}},d=h["extra"];d.attributes[A]=v,m2(c,z).then(c=>{const l=e2({...h,icons:{main:c,mask:_1()},prefix:z,iconName:a,extra:d,watchable:!0}),s=b.createElementNS("http://www.w3.org/2000/svg","svg");"::before"===v?u.insertBefore(s,u.firstChild):u.appendChild(s),s.outerHTML=l.map(c=>g1(c)).join("\n"),u.removeAttribute(p),e()}).catch(l)}}else e()})}function T2(c){return Promise.all([I2(c,"::before"),I2(c,"::after")])}function R2(c){return!(c.parentNode===document.head||~O.indexOf(c.tagName.toUpperCase())||c.getAttribute(A)||c.parentNode&&"svg"===c.parentNode.tagName)}function D2(a){if(m)return new Promise((c,l)=>{var s=M1(a.querySelectorAll("*")).filter(R2).map(T2);const z=n2.begin("searchPseudoElements");b2(),Promise.all(s).then(()=>{z(),H2(),c()}).catch(()=>{z(),H2(),l()})})}let _2=!1;const Y2=c=>{return c.toLowerCase().split(" ").reduce((c,l)=>{const s=l.toLowerCase().split("-");l=s[0];let z=s.slice(1).join("-");if(l&&"h"===z)return c.flipX=!0,c;if(l&&"v"===z)return c.flipY=!0,c;if(z=parseFloat(z),isNaN(z))return c;switch(l){case"grow":c.size=c.size+z;break;case"shrink":c.size=c.size-z;break;case"left":c.x=c.x-z;break;case"right":c.x=c.x+z;break;case"up":c.y=c.y-z;break;case"down":c.y=c.y+z;break;case"rotate":c.rotate=c.rotate+z}return c},{size:16,x:0,y:0,flipX:!1,flipY:!1,rotate:0})},W2={x:0,y:0,width:"100%",height:"100%"};function B2(c){return c.attributes&&(c.attributes.fill||(!(1{-1===Q1.indexOf(c)&&delete G1[c]}),U1.forEach(c=>{const s=c.mixout?c.mixout():{};if(Object.keys(s).forEach(l=>{"function"==typeof s[l]&&(z[l]=s[l]),"object"==typeof s[l]&&Object.keys(s[l]).forEach(c=>{z[l]||(z[l]={}),z[l][c]=s[l][c]})}),c.hooks){const l=c.hooks();Object.keys(l).forEach(c=>{X1[c]||(X1[c]=[]),X1[c].push(l[c])})}c.provides&&c.provides(G1)}),z}([H,p,V,L,v,{hooks(){return{mutationObserverCallbacks(c){return c.pseudoElementsCallback=D2,c}}},provides(c){c.pseudoElements2svg=function(c){var{node:c=b}=c;l1.searchPseudoElements&&D2(c)}}},{mixout(){return{dom:{unwatch(){b2(),_2=!0}}}},hooks(){return{bootstrap(){k2(K1("mutationObserverCallbacks",{}))},noAuto(){V2&&V2.disconnect()},watch(c){c=c.observeMutationsRoot;_2?H2():k2(K1("mutationObserverCallbacks",{observeMutationsRoot:c}))}}}},{mixout(){return{parse:{transform:c=>Y2(c)}}},hooks(){return{parseNodeAttributes(c,l){l=l.getAttribute("data-fa-transform");return l&&(c.transform=Y2(l)),c}}},provides(c){c.generateAbstractTransformGrouping=function(c){var{main:l,transform:s,containerWidth:z,iconWidth:a}=c,e={transform:"translate(".concat(z/2," 256)")},c="translate(".concat(32*s.x,", ").concat(32*s.y,") "),z="scale(".concat(s.size/16*(s.flipX?-1:1),", ").concat(s.size/16*(s.flipY?-1:1),") "),s="rotate(".concat(s.rotate," 0 0)");const L=e,M={transform:"".concat(c," ").concat(z," ").concat(s)},t={transform:"translate(".concat(a/2*-1," -256)")};return{tag:"g",attributes:{...L},children:[{tag:"g",attributes:{...M},children:[{tag:l.icon.tag,children:l.icon.children,attributes:{...l.icon.attributes,...t}}]}]}}}},{hooks(){return{parseNodeAttributes(c,l){const s=l.getAttribute("data-fa-mask"),z=s?B1(s.split(" ").map(c=>c.trim())):_1();return z.prefix||(z.prefix=q1),c.mask=z,c.maskId=l.getAttribute("data-fa-mask-id"),c}}},provides(c){c.generateAbstractMask=function(c){let{children:l,attributes:s,main:z,mask:a,maskId:e,transform:L}=c;const{width:M,icon:t}=z;var{width:r,icon:m}=a,C=function(c){var{transform:l,containerWidth:s,iconWidth:z}=c,a={transform:"translate(".concat(s/2," 256)")},c="translate(".concat(32*l.x,", ").concat(32*l.y,") "),s="scale(".concat(l.size/16*(l.flipX?-1:1),", ").concat(l.size/16*(l.flipY?-1:1),") "),l="rotate(".concat(l.rotate," 0 0)");return{outer:a,inner:{transform:"".concat(c," ").concat(s," ").concat(l)},path:{transform:"translate(".concat(z/2*-1," -256)")}}}({transform:L,containerWidth:r,iconWidth:M}),i={tag:"rect",attributes:{...W2,fill:"white"}},c=t.children?{children:t.children.map(B2)}:{},r={tag:"g",attributes:{...C.inner},children:[B2({tag:t.tag,attributes:{...t.attributes,...C.path},...c})]},c={tag:"g",attributes:{...C.outer},children:[r]},C="mask-".concat(e||L1()),r="clip-".concat(e||L1()),c={tag:"mask",attributes:{...W2,id:C,maskUnits:"userSpaceOnUse",maskContentUnits:"userSpaceOnUse"},children:[i,c]},c={tag:"defs",children:[{tag:"clipPath",attributes:{id:r},children:"g"===(m=m).tag?m.children:[m]},c]};return l.push(c,{tag:"rect",attributes:{fill:"currentColor","clip-path":"url(#".concat(r,")"),mask:"url(#".concat(C,")"),...W2}}),{children:l,attributes:s}}}},{provides(c){let e=!1;g.matchMedia&&(e=g.matchMedia("(prefers-reduced-motion: reduce)").matches),c.missingIconAbstract=function(){const c=[];var l={fill:"currentColor"},s={attributeType:"XML",repeatCount:"indefinite",dur:"2s"};c.push({tag:"path",attributes:{...l,d:"M156.5,447.7l-12.6,29.5c-18.7-9.5-35.9-21.2-51.5-34.9l22.7-22.7C127.6,430.5,141.5,440,156.5,447.7z M40.6,272H8.5 c1.4,21.2,5.4,41.7,11.7,61.1L50,321.2C45.1,305.5,41.8,289,40.6,272z M40.6,240c1.4-18.8,5.2-37,11.1-54.1l-29.5-12.6 C14.7,194.3,10,216.7,8.5,240H40.6z M64.3,156.5c7.8-14.9,17.2-28.8,28.1-41.5L69.7,92.3c-13.7,15.6-25.5,32.8-34.9,51.5 L64.3,156.5z M397,419.6c-13.9,12-29.4,22.3-46.1,30.4l11.9,29.8c20.7-9.9,39.8-22.6,56.9-37.6L397,419.6z M115,92.4 c13.9-12,29.4-22.3,46.1-30.4l-11.9-29.8c-20.7,9.9-39.8,22.6-56.8,37.6L115,92.4z M447.7,355.5c-7.8,14.9-17.2,28.8-28.1,41.5 l22.7,22.7c13.7-15.6,25.5-32.9,34.9-51.5L447.7,355.5z M471.4,272c-1.4,18.8-5.2,37-11.1,54.1l29.5,12.6 c7.5-21.1,12.2-43.5,13.6-66.8H471.4z M321.2,462c-15.7,5-32.2,8.2-49.2,9.4v32.1c21.2-1.4,41.7-5.4,61.1-11.7L321.2,462z M240,471.4c-18.8-1.4-37-5.2-54.1-11.1l-12.6,29.5c21.1,7.5,43.5,12.2,66.8,13.6V471.4z M462,190.8c5,15.7,8.2,32.2,9.4,49.2h32.1 c-1.4-21.2-5.4-41.7-11.7-61.1L462,190.8z M92.4,397c-12-13.9-22.3-29.4-30.4-46.1l-29.8,11.9c9.9,20.7,22.6,39.8,37.6,56.9 L92.4,397z M272,40.6c18.8,1.4,36.9,5.2,54.1,11.1l12.6-29.5C317.7,14.7,295.3,10,272,8.5V40.6z M190.8,50 c15.7-5,32.2-8.2,49.2-9.4V8.5c-21.2,1.4-41.7,5.4-61.1,11.7L190.8,50z M442.3,92.3L419.6,115c12,13.9,22.3,29.4,30.5,46.1 l29.8-11.9C470,128.5,457.3,109.4,442.3,92.3z M397,92.4l22.7-22.7c-15.6-13.7-32.8-25.5-51.5-34.9l-12.6,29.5 C370.4,72.1,384.4,81.5,397,92.4z"}});var z={...s,attributeName:"opacity"};const a={tag:"circle",attributes:{...l,cx:"256",cy:"364",r:"28"},children:[]};return e||a.children.push({tag:"animate",attributes:{...s,attributeName:"r",values:"28;14;28;28;14;28;"}},{tag:"animate",attributes:{...z,values:"1;0;1;1;0;1;"}}),c.push(a),c.push({tag:"path",attributes:{...l,opacity:"1",d:"M263.7,312h-16c-6.6,0-12-5.4-12-12c0-71,77.4-63.9,77.4-107.8c0-20-17.8-40.2-57.4-40.2c-29.1,0-44.3,9.6-59.2,28.7 c-3.9,5-11.1,6-16.2,2.4l-13.1-9.2c-5.6-3.9-6.9-11.8-2.6-17.2c21.2-27.2,46.4-44.7,91.2-44.7c52.3,0,97.4,29.8,97.4,80.2 c0,67.6-77.4,63.5-77.4,107.8C275.7,306.6,270.3,312,263.7,312z"},children:e?[]:[{tag:"animate",attributes:{...z,values:"1;0;0;0;0;1;"}}]}),e||c.push({tag:"path",attributes:{...l,opacity:"0",d:"M232.5,134.5l7,168c0.3,6.4,5.6,11.5,12,11.5h9c6.4,0,11.7-5.1,12-11.5l7-168c0.3-6.8-5.2-12.5-12-12.5h-23 C237.7,122,232.2,127.7,232.5,134.5z"},children:[{tag:"animate",attributes:{...z,values:"0;0;1;1;0;0;"}}]}),{tag:"g",attributes:{class:"missing"},children:c}}}},{hooks(){return{parseNodeAttributes(c,l){l=l.getAttribute("data-fa-symbol");return c.symbol=null!==l&&(""===l||l),c}}}}],{mixoutsTo:s2}),function(c){try{for(var l=arguments.length,s=new Array(1{z2(),J1("bootstrap")})),h1.hooks={...h1.hooks,addPack:(c,l)=>{h1.styles[c]={...h1.styles[c]||{},...l},I1(),z2()},addPacks:c=>{c.forEach(c=>{var[l,c]=c;h1.styles[l]={...h1.styles[l]||{},...c}}),I1(),z2()},addShims:c=>{h1.shims.push(...c),I1(),z2()}}})}(); \ No newline at end of file diff --git a/public/scripts/jquery-min.js b/public/scripts/jquery-min.js new file mode 100644 index 00000000..35906b92 --- /dev/null +++ b/public/scripts/jquery-min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},m=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||m).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),b=new RegExp(ge+"|>"),A=new RegExp(g),D=new RegExp("^"+t+"$"),N={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+d),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},L=/^(?:input|select|textarea|button)$/i,j=/^h\d$/i,O=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,P=/[+~]/,H=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),q=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},R=function(){V()},M=K(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{E.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){E={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(V(e),e=e||C,T)){if(11!==d&&(u=O.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return E.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return E.call(n,a),n}else{if(u[2])return E.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return E.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||p&&p.test(t))){if(c=t,f=e,1===d&&(b.test(t)||m.test(t))){(f=P.test(t)&&X(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=k)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+G(l[o]);c=l.join(",")}try{return E.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function B(e){return e[k]=!0,e}function F(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function $(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&M(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function U(a){return B(function(o){return o=+o,B(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function X(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=C&&9===n.nodeType&&n.documentElement&&(r=(C=n).documentElement,T=!ce.isXMLDoc(C),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=C&&(t=C.defaultView)&&t.top!==t&&t.addEventListener("unload",R),le.getById=F(function(e){return r.appendChild(e).id=ce.expando,!C.getElementsByName||!C.getElementsByName(ce.expando).length}),le.disconnectedMatch=F(function(e){return i.call(e,"*")}),le.scope=F(function(){return C.querySelectorAll(":scope")}),le.cssHas=F(function(){try{return C.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(x.filter.ID=function(e){var t=e.replace(H,q);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&T){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(H,q);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&T){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},x.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&T)return t.getElementsByClassName(e)},p=[],F(function(e){var t;r.appendChild(e).innerHTML="
",e.querySelectorAll("[selected]").length||p.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+k+"-]").length||p.push("~="),e.querySelectorAll("a#"+k+"+*").length||p.push(".#.+[+~]"),e.querySelectorAll(":checked").length||p.push(":checked"),(t=C.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&p.push(":enabled",":disabled"),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||p.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||p.push(":has"),p=p.length&&new RegExp(p.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===C||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),C}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),T&&!h[t+" "]&&(!p||!p.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(H,q),e[3]=(e[3]||e[4]||e[5]||"").replace(H,q),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return N.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&A.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(H,q).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||E,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:k.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:m,!0)),C.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=m.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,E=ce(m);var S=/^(?:parents|prev(?:Until|All))/,A={children:!0,contents:!0,next:!0,prev:!0};function D(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;re=m.createDocumentFragment().appendChild(m.createElement("div")),(be=m.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),re.appendChild(be),le.checkClone=re.cloneNode(!0).cloneNode(!0).lastChild.checked,re.innerHTML="",le.noCloneChecked=!!re.cloneNode(!0).lastChild.defaultValue,re.innerHTML="",le.option=!!re.lastChild;var Te={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Ee(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function ke(e,t){for(var n=0,r=e.length;n",""]);var Se=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Me(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Ie(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function We(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===yt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=m.implementation.createHTMLDocument("")).createElement("base")).href=m.location.href,t.head.appendChild(r)):t=m),o=!n&&[],(i=C.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||K})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return R(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Qe(le.pixelPosition,function(e,t){if(t)return t=Ve(e,n),$e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return R(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var version = "3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween", + + rhtmlSuffix = /HTML$/i, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + + // Retrieve the text value of an array of DOM nodes + text: function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += jQuery.text( node ); + } + } + if ( nodeType === 1 || nodeType === 11 ) { + return elem.textContent; + } + if ( nodeType === 9 ) { + return elem.documentElement.textContent; + } + if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + isXMLDoc: function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Assume HTML when documentElement doesn't yet exist, such as inside + // document fragments. + return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var pop = arr.pop; + + +var sort = arr.sort; + + +var splice = arr.splice; + + +var whitespace = "[\\x20\\t\\r\\n\\f]"; + + +var rtrimCSS = new RegExp( + "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", + "g" +); + + + + +// Note: an element does not contain itself +jQuery.contains = function( a, b ) { + var bup = b && b.parentNode; + + return a === bup || !!( bup && bup.nodeType === 1 && ( + + // Support: IE 9 - 11+ + // IE doesn't have `contains` on SVG. + a.contains ? + a.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); +}; + + + + +// CSS string/identifier serialization +// https://drafts.csswg.org/cssom/#common-serializing-idioms +var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; + +function fcssescape( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; +} + +jQuery.escapeSelector = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + + + + +var preferredDoc = document, + pushNative = push; + +( function() { + +var i, + Expr, + outermostContext, + sortInput, + hasDuplicate, + push = pushNative, + + // Local document vars + document, + documentElement, + documentIsHTML, + rbuggyQSA, + matches, + + // Instance-specific data + expando = jQuery.expando, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + + "loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + + whitespace + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + ID: new RegExp( "^#(" + identifier + ")" ), + CLASS: new RegExp( "^\\.(" + identifier + ")" ), + TAG: new RegExp( "^(" + identifier + "|[*])" ), + ATTR: new RegExp( "^" + attributes ), + PSEUDO: new RegExp( "^" + pseudos ), + CHILD: new RegExp( + "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + bool: new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + needsContext: new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + if ( nonHex ) { + + // Strip the backslash prefix from a non-hex escape sequence + return nonHex; + } + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + return high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes; see `setDocument`. + // Support: IE 9 - 11+, Edge 12 - 18+ + // Removing the function wrapper causes a "Permission Denied" + // error in IE/Edge. + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && nodeName( elem, "fieldset" ); + }, + { dir: "parentNode", next: "legend" } + ); + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android <=4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { + apply: function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + }, + call: function( target ) { + pushNative.apply( target, slice.call( arguments, 1 ) ); + } + }; +} + +function find( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + push.call( results, elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE 9 only + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + find.contains( context, elem ) && + elem.id === m ) { + + push.call( results, elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when + // strict-comparing two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( newContext != context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = jQuery.escapeSelector( nid ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrimCSS, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties + // (see https://github.com/jquery/sizzle/issues/157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by jQuery selector module + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + return nodeName( elem, "input" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) && + elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11+ + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a jQuery selector context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [node] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +function setDocument( node ) { + var subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + documentElement = document.documentElement; + documentIsHTML = !jQuery.isXMLDoc( document ); + + // Support: iOS 7 only, IE 9 - 11+ + // Older browsers didn't support unprefixed `matches`. + matches = documentElement.matches || + documentElement.webkitMatchesSelector || + documentElement.msMatchesSelector; + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors + // (see trac-13936). + // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, + // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. + if ( documentElement.msMatchesSelector && + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 9 - 11+, Edge 12 - 18+ + subWindow.addEventListener( "unload", unloadHandler ); + } + + // Support: IE <10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + documentElement.appendChild( el ).id = jQuery.expando; + return !document.getElementsByName || + !document.getElementsByName( jQuery.expando ).length; + } ); + + // Support: IE 9 only + // Check to see if it's possible to do matchesSelector + // on a disconnected node. + support.disconnectedMatch = assert( function( el ) { + return matches.call( el, "*" ); + } ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // IE/Edge don't support the :scope pseudo-class. + support.scope = assert( function() { + return document.querySelectorAll( ":scope" ); + } ); + + // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only + // Make sure the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter.ID = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find.ID = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter.ID = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find.ID = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find.TAG = function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else { + return context.querySelectorAll( tag ); + } + }; + + // Class + Expr.find.CLASS = function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + rbuggyQSA = []; + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + documentElement.appendChild( el ).innerHTML = + "" + + ""; + + // Support: iOS <=7 - 8 only + // Boolean attributes and "value" are not treated correctly in some XML documents + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: iOS <=7 - 8 only + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: iOS 8 only + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE 9 - 11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + documentElement.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + } ); + + if ( !support.cssHas ) { + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a === document || a.ownerDocument == preferredDoc && + find.contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b === document || b.ownerDocument == preferredDoc && + find.contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + }; + + return document; +} + +find.matches = function( expr, elements ) { + return find( expr, null, null, elements ); +}; + +find.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return find( expr, document, null, [ elem ] ).length > 0; +}; + +find.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return jQuery.contains( context, elem ); +}; + + +find.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (see trac-13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + if ( val !== undefined ) { + return val; + } + + return elem.getAttribute( name ); +}; + +find.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +jQuery.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + // + // Support: Android <=4.0+ + // Testing for detecting duplicates is unpredictable so instead assume we can't + // depend on duplicate detection in all browsers without a stable sort. + hasDuplicate = !support.sortStable; + sortInput = !support.sortStable && slice.call( results, 0 ); + sort.call( results, sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + splice.call( results, duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +jQuery.fn.uniqueSort = function() { + return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) ); +}; + +Expr = jQuery.expr = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + ATTR: function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" ) + .replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + CHILD: function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + find.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) + ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + find.error( match[ 0 ] ); + } + + return match; + }, + + PSEUDO: function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr.CHILD.test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + TAG: function( nodeNameSelector ) { + var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return nodeName( elem, expectedNodeName ); + }; + }, + + CLASS: function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + ")" + className + + "(" + whitespace + "|$)" ) ) && + classCache( className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + ATTR: function( name, operator, check ) { + return function( elem ) { + var result = find.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + if ( operator === "=" ) { + return result === check; + } + if ( operator === "!=" ) { + return result !== check; + } + if ( operator === "^=" ) { + return check && result.indexOf( check ) === 0; + } + if ( operator === "*=" ) { + return check && result.indexOf( check ) > -1; + } + if ( operator === "$=" ) { + return check && result.slice( -check.length ) === check; + } + if ( operator === "~=" ) { + return ( " " + result.replace( rwhitespace, " " ) + " " ) + .indexOf( check ) > -1; + } + if ( operator === "|=" ) { + return result === check || result.slice( 0, check.length + 1 ) === check + "-"; + } + + return false; + }; + }, + + CHILD: function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + nodeName( node, name ) : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || ( parent[ expando ] = {} ); + cache = outerCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + cache = outerCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + nodeName( node, name ) : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + outerCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + PSEUDO: function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // https://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + find.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as jQuery does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + not: markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrimCSS, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element + // (see https://github.com/jquery/sizzle/issues/299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + has: markFunction( function( selector ) { + return function( elem ) { + return find( selector, elem ).length > 0; + }; + } ), + + contains: markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // https://www.w3.org/TR/selectors/#lang-pseudo + lang: markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + find.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + target: function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + root: function( elem ) { + return elem === documentElement; + }, + + focus: function( elem ) { + return elem === safeActiveElement() && + document.hasFocus() && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + enabled: createDisabledPseudo( false ), + disabled: createDisabledPseudo( true ), + + checked: function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + return ( nodeName( elem, "input" ) && !!elem.checked ) || + ( nodeName( elem, "option" ) && !!elem.selected ); + }, + + selected: function( elem ) { + + // Support: IE <=11+ + // Accessing the selectedIndex property + // forces the browser to treat the default option as + // selected when in an optgroup. + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + empty: function( elem ) { + + // https://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + parent: function( elem ) { + return !Expr.pseudos.empty( elem ); + }, + + // Element/input types + header: function( elem ) { + return rheader.test( elem.nodeName ); + }, + + input: function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + button: function( elem ) { + return nodeName( elem, "input" ) && elem.type === "button" || + nodeName( elem, "button" ); + }, + + text: function( elem ) { + var attr; + return nodeName( elem, "input" ) && elem.type === "text" && + + // Support: IE <10 only + // New HTML5 attribute values (e.g., "search") appear + // with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + first: createPositionalPseudo( function() { + return [ 0 ]; + } ), + + last: createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + eq: createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + even: createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + odd: createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + lt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i; + + if ( argument < 0 ) { + i = argument + length; + } else if ( argument > length ) { + i = length; + } else { + i = argument; + } + + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + gt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos.nth = Expr.pseudos.eq; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rleadingCombinator.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrimCSS, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + if ( parseOnly ) { + return soFar.length; + } + + return soFar ? + find.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + if ( skip && nodeName( elem, skip ) ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = outerCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + outerCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + find( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, matcherOut, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || + multipleContexts( selector || "*", + context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems; + + if ( matcher ) { + + // If we have a postFinder, or filtered seed, or non-seed postFilter + // or preexisting results, + matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results; + + // Find primary matches + matcher( matcherIn, matcherOut, context, xml ); + } else { + matcherOut = matcherIn; + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element + // (see https://github.com/jquery/sizzle/issues/299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrimCSS, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find.TAG( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: iOS <=7 - 9 only + // Tolerate NodeList properties (IE: "length"; Safari: ) matching + // elements by id. (see trac-14142) + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + push.call( results, elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + jQuery.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +function compile( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +} + +/** + * A low-level selection function that works with jQuery's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with jQuery selector compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find.ID( + token.matches[ 0 ].replace( runescape, funescape ), + context + ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && + testContext( context.parentNode ) || context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +} + +// One-time assignments + +// Support: Android <=4.0 - 4.1+ +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Initialize against the default document +setDocument(); + +// Support: Android <=4.0 - 4.1+ +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +jQuery.find = find; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.unique = jQuery.uniqueSort; + +// These have always been private, but they used to be documented as part of +// Sizzle so let's maintain them for now for backwards compatibility purposes. +find.compile = compile; +find.select = select; +find.setDocument = setDocument; +find.tokenize = tokenize; + +find.escape = jQuery.escapeSelector; +find.getText = jQuery.text; +find.isXML = jQuery.isXMLDoc; +find.selectors = jQuery.expr; +find.support = jQuery.support; +find.uniqueSort = jQuery.uniqueSort; + + /* eslint-enable */ + +} )(); + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (trac-9521) + // Strict HTML recognition (trac-11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to jQuery#find + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.error ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the error, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getErrorHook ) { + process.error = jQuery.Deferred.getErrorHook(); + + // The deprecated alias of the above. While the name suggests + // returning the stack, not an error instance, jQuery just passes + // it directly to `console.warn` so both will work; an instance + // just better cooperates with source maps. + } else if ( jQuery.Deferred.getStackHook ) { + process.error = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error +// captured before the async barrier to get the original error cause +// which may otherwise be hidden. +jQuery.Deferred.exceptionHook = function( error, asyncError ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, + error.stack, asyncError ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See trac-6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (trac-9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see trac-8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (trac-14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (trac-11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (trac-14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (trac-13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (trac-12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (trac-13208) + // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (trac-13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", true ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, isSetup ) { + + // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add + if ( !isSetup ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + if ( !saved ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + this[ type ](); + result = dataPriv.get( this, type ); + dataPriv.set( this, type, false ); + + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + return result; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering + // the native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved ) { + + // ...and capture the result + dataPriv.set( this, type, jQuery.event.trigger( + saved[ 0 ], + saved.slice( 1 ), + this + ) ); + + // Abort handling of the native event by all jQuery handlers while allowing + // native handlers on the same element to run. On target, this is achieved + // by stopping immediate propagation just on the jQuery event. However, + // the native event is re-wrapped by a jQuery one on each level of the + // propagation so the only way to stop it for jQuery is to stop it for + // everyone via native `stopPropagation()`. This is not a problem for + // focus/blur which don't bubble, but it does also stop click on checkboxes + // and radios. We accept this limitation. + event.stopPropagation(); + event.isImmediatePropagationStopped = returnTrue; + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (trac-504, trac-13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + + function focusMappedHandler( nativeEvent ) { + if ( document.documentMode ) { + + // Support: IE 11+ + // Attach a single focusin/focusout handler on the document while someone wants + // focus/blur. This is because the former are synchronous in IE while the latter + // are async. In other browsers, all those handlers are invoked synchronously. + + // `handle` from private data would already wrap the event, but we need + // to change the `type` here. + var handle = dataPriv.get( this, "handle" ), + event = jQuery.event.fix( nativeEvent ); + event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; + event.isSimulated = true; + + // First, handle focusin/focusout + handle( nativeEvent ); + + // ...then, handle focus/blur + // + // focus/blur don't bubble while focusin/focusout do; simulate the former by only + // invoking the handler at the lower level. + if ( event.target === event.currentTarget ) { + + // The setup part calls `leverageNative`, which, in turn, calls + // `jQuery.event.add`, so event handle will already have been set + // by this point. + handle( event ); + } + } else { + + // For non-IE browsers, attach a single capturing handler on the document + // while someone wants focusin/focusout. + jQuery.event.simulate( delegateType, nativeEvent.target, + jQuery.event.fix( nativeEvent ) ); + } + } + + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + var attaches; + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, true ); + + if ( document.documentMode ) { + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + attaches = dataPriv.get( this, delegateType ); + if ( !attaches ) { + this.addEventListener( delegateType, focusMappedHandler ); + } + dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 ); + } else { + + // Return false to allow normal processing in the caller + return false; + } + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + teardown: function() { + var attaches; + + if ( document.documentMode ) { + attaches = dataPriv.get( this, delegateType ) - 1; + if ( !attaches ) { + this.removeEventListener( delegateType, focusMappedHandler ); + dataPriv.remove( this, delegateType ); + } else { + dataPriv.set( this, delegateType, attaches ); + } + } else { + + // Return false to indicate standard teardown should be applied + return false; + } + }, + + // Suppress native focus or blur if we're currently inside + // a leveraged native-event stack + _default: function( event ) { + return dataPriv.get( event.target, type ); + }, + + delegateType: delegateType + }; + + // Support: Firefox <=44 + // Firefox doesn't have focus(in | out) events + // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 + // + // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 + // focus(in | out) events fire after focus & blur events, + // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order + // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 + // + // Support: IE 9 - 11+ + // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, + // attach a single handler for both events in IE. + jQuery.event.special[ delegateType ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ); + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + if ( !attaches ) { + if ( document.documentMode ) { + this.addEventListener( delegateType, focusMappedHandler ); + } else { + doc.addEventListener( type, focusMappedHandler, true ); + } + } + dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ) - 1; + + if ( !attaches ) { + if ( document.documentMode ) { + this.removeEventListener( delegateType, focusMappedHandler ); + } else { + doc.removeEventListener( type, focusMappedHandler, true ); + } + dataPriv.remove( dataHolder, delegateType ); + } else { + dataPriv.set( dataHolder, delegateType, attaches ); + } + } + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (trac-8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Re-enable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + + // Unwrap a CDATA section containing script contents. This shouldn't be + // needed as in XML documents they're already not visible when + // inspecting element contents and in HTML documents they have no + // meaning but we're preserving that logic for backwards compatibility. + // This will be removed completely in 4.0. See gh-4904. + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew jQuery#find here for performance reasons: + // https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var rcustomProp = /^--/; + + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (trac-8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "box-sizing:content-box;border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is `display: block` + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + isCustomProp = rcustomProp.test( name ), + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, trac-12537) + // .css('--customProperty) (gh-3144) + if ( computed ) { + + // Support: IE <=9 - 11+ + // IE only supports `"float"` in `getPropertyValue`; in computed styles + // it's only available as `"cssFloat"`. We no longer modify properties + // sent to `.css()` apart from camelCasing, so we need to check both. + // Normally, this would create difference in behavior: if + // `getPropertyValue` returns an empty string, the value returned + // by `.css()` would be `undefined`. This is usually the case for + // disconnected elements. However, in IE even disconnected elements + // with no styles return `"none"` for `getPropertyValue( "float" )` + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( isCustomProp && ret ) { + + // Support: Firefox 105+, Chrome <=105+ + // Spec requires trimming whitespace for custom properties (gh-4926). + // Firefox only trims leading whitespace. Chrome just collapses + // both leading & trailing whitespace to a single space. + // + // Fall back to `undefined` if empty string returned. + // This collapses a missing definition with property defined + // and set to an empty string but there's no standard API + // allowing us to differentiate them without a performance penalty + // and returning `undefined` aligns with older jQuery. + // + // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED + // as whitespace while CSS does not, but this is not a problem + // because CSS preprocessing replaces them with U+000A LINE FEED + // (which *is* CSS whitespace) + // https://www.w3.org/TR/css-syntax-3/#input-preprocessing + ret = ret.replace( rtrimCSS, "$1" ) || undefined; + } + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0, + marginDelta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + // Count margin delta separately to only add it after scroll gutter adjustment. + // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). + if ( box === "margin" ) { + marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta + marginDelta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + animationIterationCount: true, + aspectRatio: true, + borderImageSlice: true, + columnCount: true, + flexGrow: true, + flexShrink: true, + fontWeight: true, + gridArea: true, + gridColumn: true, + gridColumnEnd: true, + gridColumnStart: true, + gridRow: true, + gridRowEnd: true, + gridRowStart: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + scale: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeMiterlimit: true, + strokeOpacity: true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (trac-7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug trac-9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (trac-7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +// Based off of the plugin by Clint Helfers, with permission. +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // Use proper attribute retrieval (trac-12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classNames, cur, curValue, className, i, finalValue; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classNames = classesToArray( value ); + + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + if ( cur.indexOf( " " + className + " " ) < 0 ) { + cur += className + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + this.setAttribute( "class", finalValue ); + } + } + } ); + } + + return this; + }, + + removeClass: function( value ) { + var classNames, cur, curValue, className, i, finalValue; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classNames = classesToArray( value ); + + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + + // This expression is here for better compressibility (see addClass) + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + + // Remove *all* instances + while ( cur.indexOf( " " + className + " " ) > -1 ) { + cur = cur.replace( " " + className + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + this.setAttribute( "class", finalValue ); + } + } + } ); + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var classNames, className, i, self, + type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + classNames = classesToArray( value ); + + return this.each( function() { + if ( isValidValue ) { + + // Toggle individual class names + self = jQuery( this ); + + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (trac-14686, trac-14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (trac-2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (trac-9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (trac-6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +// Support: Safari 8 only +// In Safari 8 documents created via document.implementation.createHTMLDocument +// collapse sibling forms: the second one becomes a child of the first one. +// Because of that, this security measure has to be disabled in Safari 8. +// https://bugs.webkit.org/show_bug.cgi?id=137337 +support.createHTMLDocument = ( function() { + var body = document.implementation.createHTMLDocument( "" ).body; + body.innerHTML = "
"; + return body.childNodes.length === 2; +} )(); + + +// Argument "data" should be string of html +// context (optional): If specified, the fragment will be created in this context, +// defaults to document +// keepScripts (optional): If true, will include scripts passed in the html string +jQuery.parseHTML = function( data, context, keepScripts ) { + if ( typeof data !== "string" ) { + return []; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + + var base, parsed, scripts; + + if ( !context ) { + + // Stop scripts or inline event handlers from being executed immediately + // by using document.implementation + if ( support.createHTMLDocument ) { + context = document.implementation.createHTMLDocument( "" ); + + // Set the base href for the created document + // so any parsed elements with URLs + // are based on the document's URL (gh-2965) + base = context.createElement( "base" ); + base.href = document.location.href; + context.head.appendChild( base ); + } else { + context = document; + } + } + + parsed = rsingleTag.exec( data ); + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[ 1 ] ) ]; + } + + parsed = buildFragment( [ data ], context, scripts ); + + if ( scripts && scripts.length ) { + jQuery( scripts ).remove(); + } + + return jQuery.merge( [], parsed.childNodes ); +}; + + +jQuery.offset = { + setOffset: function( elem, options, i ) { + var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, + position = jQuery.css( elem, "position" ), + curElem = jQuery( elem ), + props = {}; + + // Set position first, in-case top/left are set even on static elem + if ( position === "static" ) { + elem.style.position = "relative"; + } + + curOffset = curElem.offset(); + curCSSTop = jQuery.css( elem, "top" ); + curCSSLeft = jQuery.css( elem, "left" ); + calculatePosition = ( position === "absolute" || position === "fixed" ) && + ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; + + // Need to be able to calculate position if either + // top or left is auto and position is either absolute or fixed + if ( calculatePosition ) { + curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; + } + + if ( isFunction( options ) ) { + + // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) + options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); + } + + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; + } + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; + } + + if ( "using" in options ) { + options.using.call( elem, props ); + + } else { + curElem.css( props ); + } + } +}; + +jQuery.fn.extend( { + + // offset() relates an element's border box to the document origin + offset: function( options ) { + + // Preserve chaining for setter + if ( arguments.length ) { + return options === undefined ? + this : + this.each( function( i ) { + jQuery.offset.setOffset( this, options, i ); + } ); + } + + var rect, win, + elem = this[ 0 ]; + + if ( !elem ) { + return; + } + + // Return zeros for disconnected and hidden (display: none) elements (gh-2310) + // Support: IE <=11 only + // Running getBoundingClientRect on a + // disconnected node in IE throws an error + if ( !elem.getClientRects().length ) { + return { top: 0, left: 0 }; + } + + // Get document-relative position by adding viewport scroll to viewport-relative gBCR + rect = elem.getBoundingClientRect(); + win = elem.ownerDocument.defaultView; + return { + top: rect.top + win.pageYOffset, + left: rect.left + win.pageXOffset + }; + }, + + // position() relates an element's margin box to its offset parent's padding box + // This corresponds to the behavior of CSS absolute positioning + position: function() { + if ( !this[ 0 ] ) { + return; + } + + var offsetParent, offset, doc, + elem = this[ 0 ], + parentOffset = { top: 0, left: 0 }; + + // position:fixed elements are offset from the viewport, which itself always has zero offset + if ( jQuery.css( elem, "position" ) === "fixed" ) { + + // Assume position:fixed implies availability of getBoundingClientRect + offset = elem.getBoundingClientRect(); + + } else { + offset = this.offset(); + + // Account for the *real* offset parent, which can be the document or its root element + // when a statically positioned element is identified + doc = elem.ownerDocument; + offsetParent = elem.offsetParent || doc.documentElement; + while ( offsetParent && + ( offsetParent === doc.body || offsetParent === doc.documentElement ) && + jQuery.css( offsetParent, "position" ) === "static" ) { + + offsetParent = offsetParent.parentNode; + } + if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) { + + // Incorporate borders into its offset, since they are outside its content origin + parentOffset = jQuery( offsetParent ).offset(); + parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true ); + parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true ); + } + } + + // Subtract parent offsets and element margins + return { + top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), + left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) + }; + }, + + // This method will return documentElement in the following cases: + // 1) For the element inside the iframe without offsetParent, this method will return + // documentElement of the parent window + // 2) For the hidden or detached element + // 3) For body or html element, i.e. in case of the html node - it will return itself + // + // but those exceptions were never presented as a real life use-cases + // and might be considered as more preferable results. + // + // This logic, however, is not guaranteed and can change at any point in the future + offsetParent: function() { + return this.map( function() { + var offsetParent = this.offsetParent; + + while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { + offsetParent = offsetParent.offsetParent; + } + + return offsetParent || documentElement; + } ); + } +} ); + +// Create scrollLeft and scrollTop methods +jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { + var top = "pageYOffset" === prop; + + jQuery.fn[ method ] = function( val ) { + return access( this, function( elem, method, val ) { + + // Coalesce documents and windows + var win; + if ( isWindow( elem ) ) { + win = elem; + } else if ( elem.nodeType === 9 ) { + win = elem.defaultView; + } + + if ( val === undefined ) { + return win ? win[ prop ] : elem[ method ]; + } + + if ( win ) { + win.scrollTo( + !top ? val : win.pageXOffset, + top ? val : win.pageYOffset + ); + + } else { + elem[ method ] = val; + } + }, method, val, arguments.length ); + }; +} ); + +// Support: Safari <=7 - 9.1, Chrome <=37 - 49 +// Add the top/left cssHooks using jQuery.fn.position +// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 +// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 +// getComputedStyle returns percent when specified for top/left/bottom/right; +// rather than make the css module depend on the offset module, just check for it here +jQuery.each( [ "top", "left" ], function( _i, prop ) { + jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, + function( elem, computed ) { + if ( computed ) { + computed = curCSS( elem, prop ); + + // If curCSS returns percentage, fallback to offset + return rnumnonpx.test( computed ) ? + jQuery( elem ).position()[ prop ] + "px" : + computed; + } + } + ); +} ); + + +// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + jQuery.each( { + padding: "inner" + name, + content: type, + "": "outer" + name + }, function( defaultExtra, funcName ) { + + // Margin is only for outerHeight, outerWidth + jQuery.fn[ funcName ] = function( margin, value ) { + var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), + extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); + + return access( this, function( elem, type, value ) { + var doc; + + if ( isWindow( elem ) ) { + + // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) + return funcName.indexOf( "outer" ) === 0 ? + elem[ "inner" + name ] : + elem.document.documentElement[ "client" + name ]; + } + + // Get document width or height + if ( elem.nodeType === 9 ) { + doc = elem.documentElement; + + // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], + // whichever is greatest + return Math.max( + elem.body[ "scroll" + name ], doc[ "scroll" + name ], + elem.body[ "offset" + name ], doc[ "offset" + name ], + doc[ "client" + name ] + ); + } + + return value === undefined ? + + // Get width or height on the element, requesting but not forcing parseFloat + jQuery.css( elem, type, extra ) : + + // Set width or height on the element + jQuery.style( elem, type, value, extra ); + }, type, chainable ? margin : undefined, chainable ); + }; + } ); +} ); + + +jQuery.fn.extend( { + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? + this.off( selector, "**" ) : + this.off( types, selector || "**", fn ); + }, + + hover: function( fnOver, fnOut ) { + return this + .on( "mouseenter", fnOver ) + .on( "mouseleave", fnOut || fnOver ); + } +} ); + +jQuery.each( + ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( _i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + } +); + + + + +// Support: Android <=4.0 only +// Make sure we trim BOM and NBSP +// Require that the "whitespace run" starts from a non-whitespace +// to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position. +var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g; + +// Bind a function to a context, optionally partially applying any +// arguments. +// jQuery.proxy is deprecated to promote standards (specifically Function#bind) +// However, it is not slated for removal any time soon +jQuery.proxy = function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; +}; + +jQuery.holdReady = function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } +}; +jQuery.isArray = Array.isArray; +jQuery.parseJSON = JSON.parse; +jQuery.nodeName = nodeName; +jQuery.isFunction = isFunction; +jQuery.isWindow = isWindow; +jQuery.camelCase = camelCase; +jQuery.type = toType; + +jQuery.now = Date.now; + +jQuery.isNumeric = function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); +}; + +jQuery.trim = function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "$1" ); +}; + + + +// Register as a named AMD module, since jQuery can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase jquery is used because AMD module names are +// derived from file names, and jQuery is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + +if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function() { + return jQuery; + } ); +} + + + + +var + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$; + +jQuery.noConflict = function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; +}; + +// Expose jQuery and $ identifiers, even in AMD +// (trac-7102#comment:10, https://github.com/jquery/jquery/pull/557) +// and CommonJS for browser emulators (trac-13566) +if ( typeof noGlobal === "undefined" ) { + window.jQuery = window.$ = jQuery; +} + + + + +return jQuery; +} ); diff --git a/public/scripts/marked-min.js b/public/scripts/marked-min.js new file mode 100644 index 00000000..bbbc3fe2 --- /dev/null +++ b/public/scripts/marked-min.js @@ -0,0 +1,11 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,function(n){"use strict";function e(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function t(e){n.defaults=e}n.defaults=e();const s=/[&<>"']/,Q=new RegExp(s.source,"g"),r=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,B=new RegExp(r.source,"g"),M={"&":"&","<":"<",">":">",'"':""","'":"'"},i=e=>M[e];function l(e,t){if(t){if(s.test(e))return e.replace(Q,i)}else if(r.test(e))return e.replace(B,i);return e}const O=/(^|[^\[])\^/g;function a(e,t){let s="string"==typeof e?e:e.source;t=t||"";const r={replace:(e,t)=>{let n="string"==typeof t?t:t.source;return n=n.replace(O,"$1"),s=s.replace(e,n),r},getRegex:()=>new RegExp(s,t)};return r}function o(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch{return null}return e}var c={exec:()=>null};function h(e,t){const n=e.replace(/\|/g,(e,t,n)=>{let s=!1,r=t;for(;0<=--r&&"\\"===n[r];)s=!s;return s?"|":" |"}),s=n.split(/ \|/);let r=0;if(s[0].trim()||s.shift(),0t)s.splice(t);else for(;s.length{var t=e.match(/^\s+/);if(null===t)return e;var[t]=t;return t.length>=n.length?e.slice(n.length):e}).join("\n")}(e=t[0],t[3]||""),{type:"code",raw:e,lang:t[2]&&t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"),text:n}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const n=u(e,"#");!this.options.pedantic&&n&&!/ $/.test(n)||(e=n.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){e=this.rules.block.hr.exec(e);if(e)return{type:"hr",raw:u(e[0],"\n")}}blockquote(e){e=this.rules.block.blockquote.exec(e);if(e){let n=u(e[0],"\n").split("\n"),s="",r="";const o=[];for(;0/.test(n[t]))c.push(n[t]),e=!0;else{if(e)break;c.push(n[t])}n=n.slice(t);const h=c.join("\n");var i=h.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1").replace(/^ {0,3}>[ \t]?/gm,""),l=(s=s?s+` +`+h:h,r=r?r+` +`+i:i,this.lexer.state.top);if(this.lexer.state.top=!0,this.lexer.blockTokens(i,o,!0),this.lexer.state.top=l,0===n.length)break;i=o[o.length-1];if("code"===i?.type)break;if("blockquote"===i?.type){var l=i,a=l.raw+"\n"+n.join("\n"),a=this.blockquote(a);o[o.length-1]=a,s=s.substring(0,s.length-l.raw.length)+a.raw,r=r.substring(0,r.length-l.text.length)+a.text;break}if("list"===i?.type){l=i;const p=l.raw+"\n"+n.join("\n");a=this.list(p);o[o.length-1]=a,s=s.substring(0,s.length-i.raw.length)+a.raw,r=r.substring(0,r.length-l.raw.length)+a.raw,n=p.substring(o[o.length-1].raw.length).split("\n")}}return{type:"blockquote",raw:s,tokens:o,text:r}}}list(h){let p=this.rules.block.list.exec(h);if(p){let e=p[1].trim();var t=1" ".repeat(3*e.length)),r=h.split("\n",1)[0],i=!s.trim(),l=0;if(this.options.pedantic?(l=2,n=s.trimStart()):i?l=p[1].length+1:(l=4<(l=p[2].search(/[^ ]/))?1:l,n=s.slice(l),l+=p[1].length),i&&/^[ \t]*$/.test(r)&&(t+=r+"\n",h=h.substring(r.length+1),e=!0),!e){const f=new RegExp(`^ {0,${Math.min(3,l-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),d=new RegExp(`^ {0,${Math.min(3,l-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),x=new RegExp(`^ {0,${Math.min(3,l-1)}}(?:\`\`\`|~~~)`),b=new RegExp(`^ {0,${Math.min(3,l-1)}}#`),w=new RegExp(`^ {0,${Math.min(3,l-1)}}<[a-z].*>`,"i");for(;h;){var u=h.split("\n",1)[0];let e;if(r=u,e=this.options.pedantic?r=r.replace(/^ {1,4}(?=( {4})*[^ ])/g," "):r.replace(/\t/g," "),x.test(r))break;if(b.test(r))break;if(w.test(r))break;if(f.test(r))break;if(d.test(r))break;if(e.search(/[^ ]/)>=l||!r.trim())n+="\n"+e.slice(l);else{if(i)break;if(4<=s.replace(/\t/g," ").search(/[^ ]/))break;if(x.test(s))break;if(b.test(s))break;if(d.test(s))break;n+="\n"+r}i||r.trim()||(i=!0),t+=u+"\n",h=h.substring(u.length+1),s=e.slice(l)}}k.loose||(c?k.loose=!0:/\n[ \t]*\n[ \t]*$/.test(t)&&(c=!0));let a=null,o;this.options.gfm&&(a=/^\[[ xX]\] /.exec(n))&&(o="[ ] "!==a[0],n=n.replace(/^\[[ xX]\] +/,"")),k.items.push({type:"list_item",raw:t,task:!!a,checked:o,loose:!1,text:n,tokens:[]}),k.raw+=t}k.items[k.items.length-1].raw=k.items[k.items.length-1].raw.trimEnd(),k.items[k.items.length-1].text=k.items[k.items.length-1].text.trimEnd(),k.raw=k.raw.trimEnd();for(let e=0;e"space"===e.type);var n=0/\n.*\n/.test(e.raw));k.loose=n}if(k.loose)for(let e=0;e$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]&&t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"),{type:"def",tag:e,raw:t[0],href:n,title:s}}table(e){const t=this.rules.block.table.exec(e);if(t&&/[:|]/.test(t[2])){var n=h(t[1]),e=t[2].replace(/^\||\| *$/g,"").split("|"),s=t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[];const r={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===e.length){for(const i of e)/^ *-+: *$/.test(i)?r.align.push("right"):/^ *:-+: *$/.test(i)?r.align.push("center"):/^ *:-+ *$/.test(i)?r.align.push("left"):r.align.push(null);for(let e=0;e({text:e,tokens:this.lexer.inline(e),header:!1,align:r.align[t]})));return r}}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t)return e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1],{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}text(e){e=this.rules.block.text.exec(e);if(e)return{type:"text",raw:e[0],text:e[0],tokens:this.lexer.inline(e[0])}}escape(e){e=this.rules.inline.escape.exec(e);if(e)return{type:"escape",raw:e[0],text:l(e[1])}}tag(e){e=this.rules.inline.tag.exec(e);if(e)return!this.lexer.state.inLink&&/^/i.test(e[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:e[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:e[0]}}link(n){const s=this.rules.inline.link.exec(n);if(s){const i=s[2].trim();if(!this.options.pedantic&&/^$/.test(i))return;n=u(i.slice(0,-1),"\\");if((i.length-n.length)%2==0)return}else{var r,n=function(t,n){if(-1===t.indexOf(n[1]))return-1;let s=0;for(let e=0;e$/.test(i)?e.slice(1):e.slice(1,-1)),j(s,{href:e&&e.replace(this.rules.inline.anyPunctuation,"$1"),title:t&&t.replace(this.rules.inline.anyPunctuation,"$1")},s[0],this.lexer)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const s=(n[2]||n[1]).replace(/\s+/g," ");e=t[s.toLowerCase()];return e?j(n,e,n[0],this.lexer):{type:"text",raw:t=n[0].charAt(0),text:t}}}emStrong(r,i,e=""){let l=this.rules.inline.emStrongLDelim.exec(r);if(l&&((!l[3]||!e.match(/[\p{L}\p{N}]/u))&&(!(l[1]||l[2]||"")||!e||this.rules.inline.punctuation.exec(e)))){var a=[...l[0]].length-1;let e,t,n=a,s=0;const c="*"===l[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(c.lastIndex=0,i=i.slice(-1*r.length+a);null!=(l=c.exec(i));)if(e=l[1]||l[2]||l[3]||l[4]||l[5]||l[6])if(t=[...e].length,l[3]||l[4])n+=t;else if((l[5]||l[6])&&a%3&&!((a+t)%3))s+=t;else if(!(0<(n-=t))){t=Math.min(t,t+n+s);var o=[...l[0]][0].length;const h=r.slice(0,a+l.index+o+t);if(Math.min(a,t)%2)return o=h.slice(1,-1),{type:"em",raw:h,text:o,tokens:this.lexer.inlineTokens(o)};o=h.slice(2,-2);return{type:"strong",raw:h,text:o,tokens:this.lexer.inlineTokens(o)}}}}codespan(t){const n=this.rules.inline.code.exec(t);if(n){let e=n[2].replace(/\n/g," ");var t=/[^ ]/.test(e),s=/^ /.test(e)&&/ $/.test(e);return e=l(e=t&&s?e.substring(1,e.length-1):e,!0),{type:"codespan",raw:n[0],text:e}}}br(e){e=this.rules.inline.br.exec(e);if(e)return{type:"br",raw:e[0]}}del(e){e=this.rules.inline.del.exec(e);if(e)return{type:"del",raw:e[0],text:e[2],tokens:this.lexer.inlineTokens(e[2])}}autolink(n){n=this.rules.inline.autolink.exec(n);if(n){let e,t;return t="@"===n[2]?"mailto:"+(e=l(n[1])):e=l(n[1]),{type:"link",raw:n[0],text:e,href:t,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let n;if(n=this.rules.inline.url.exec(e)){let e,t;if("@"===n[2])e=l(n[0]),t="mailto:"+e;else{for(var s;s=n[0],n[0]=this.rules.inline._backpedal.exec(n[0])?.[0]??"",s!==n[0];);e=l(n[0]),t="www."===n[1]?"http://"+n[0]:n[0]}return{type:"link",raw:n[0],text:e,href:t,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(t){t=this.rules.inline.text.exec(t);if(t){let e;return e=this.lexer.state.inRawBlock?t[0]:l(t[0]),{type:"text",raw:t[0],text:e}}}}var p=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,k=/(?:[*+-]|\d{1,9}[.)])/,g=a(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,k).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),f=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,d=/(?!\s*\])(?:\\.|[^\[\]\\])+/,x=a(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",d).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),k=a(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,k).getRegex(),b="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",w=/|$))/,y=a("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))","i").replace("comment",w).replace("tag",b).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),$=a(f).replace("hr",p).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",b).getRegex(),x={blockquote:a(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",$).getRegex(),code:/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,def:x,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:p,html:y,lheading:g,list:k,newline:/^(?:[ \t]*(?:\n|$))+/,paragraph:$,table:c,text:/^[^\n]+/},y=a("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",p).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3}\t)[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",b).getRegex(),k={...x,table:y,paragraph:a(f).replace("hr",p).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",y).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",b).getRegex()},$={...x,html:a("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",w).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:c,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:a(f).replace("hr",p).replace("heading"," *#{1,6} *[^\n]").replace("lheading",g).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},y=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,b=/^( {2,}|\\)\n(?!\s*$)/,f="\\p{P}\\p{S}",p=a(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,f).getRegex(),g=a(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,f).getRegex(),D=a("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,f).getRegex(),z=a("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,f).getRegex(),f=a(/\\([punct])/,"gu").replace(/punct/g,f).getRegex(),C=a(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),w=a(w).replace("(?:--\x3e|$)","--\x3e").getRegex(),w=a("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",w).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),v=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,R=a(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",v).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),T=a(/^!?\[(label)\]\[(ref)\]/).replace("label",v).replace("ref",d).getRegex(),d=a(/^!?\[(ref)\](?:\[\])?/).replace("ref",d).getRegex(),f={_backpedal:c,anyPunctuation:f,autolink:C,blockSkip:/\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g,br:b,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:c,emStrongLDelim:g,emStrongRDelimAst:D,emStrongRDelimUnd:z,escape:y,link:R,nolink:d,punctuation:p,reflink:T,reflinkSearch:a("reflink|nolink(?!\\()","g").replace("reflink",T).replace("nolink",d).getRegex(),tag:w,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\!!(n=e.call({lexer:this},s,t))&&(s=s.substring(n.raw.length),t.push(n),!0))))if(n=this.tokenizer.space(s))s=s.substring(n.raw.length),1===n.raw.length&&0{"number"==typeof(n=e.call({lexer:this},a))&&0<=n&&(t=Math.min(t,n))}),t<1/0&&0<=t&&(i=s.substring(0,t+1))}if(this.state.top&&(n=this.tokenizer.paragraph(i)))r=t[t.length-1],e&&"paragraph"===r?.type?(r.raw+="\n"+n.raw,r.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(n),e=i.length!==s.length,s=s.substring(n.raw.length);else if(n=this.tokenizer.text(s))s=s.substring(n.raw.length),(r=t[t.length-1])&&"text"===r.type?(r.raw+="\n"+n.raw,r.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(n);else if(s){var l="Infinite loop on byte: "+s.charCodeAt(0);if(this.options.silent){console.error(l);break}throw new Error(l)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(s,t=[]){let n,e,r,i=s,l,a,o;if(this.tokens.links){const h=Object.keys(this.tokens.links);if(0!!(n=e.call({lexer:this},s,t))&&(s=s.substring(n.raw.length),t.push(n),!0))))if(n=this.tokenizer.escape(s))s=s.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.tag(s))s=s.substring(n.raw.length),(e=t[t.length-1])&&"text"===n.type&&"text"===e.type?(e.raw+=n.raw,e.text+=n.text):t.push(n);else if(n=this.tokenizer.link(s))s=s.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.reflink(s,this.tokens.links))s=s.substring(n.raw.length),(e=t[t.length-1])&&"text"===n.type&&"text"===e.type?(e.raw+=n.raw,e.text+=n.text):t.push(n);else if(n=this.tokenizer.emStrong(s,i,o))s=s.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.codespan(s))s=s.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.br(s))s=s.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.del(s))s=s.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.autolink(s))s=s.substring(n.raw.length),t.push(n);else if(!this.state.inLink&&(n=this.tokenizer.url(s)))s=s.substring(n.raw.length),t.push(n);else{if(r=s,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const p=s.slice(1);let n;this.options.extensions.startInline.forEach(e=>{"number"==typeof(n=e.call({lexer:this},p))&&0<=n&&(t=Math.min(t,n))}),t<1/0&&0<=t&&(r=s.substring(0,t+1))}if(n=this.tokenizer.inlineText(r))s=s.substring(n.raw.length),"_"!==n.raw.slice(-1)&&(o=n.raw.slice(-1)),a=!0,(e=t[t.length-1])&&"text"===e.type?(e.raw+=n.raw,e.text+=n.text):t.push(n);else if(s){var c="Infinite loop on byte: "+s.charCodeAt(0);if(this.options.silent){console.error(c);break}throw new Error(c)}}return t}}class I{options;parser;constructor(e){this.options=e||n.defaults}space(e){return""}code({text:e,lang:t,escaped:n}){t=(t||"").match(/^\S*/)?.[0],e=e.replace(/\n$/,"")+"\n";return t?'
'+(n?e:l(e,!0))+"
\n":"
"+(n?e:l(e,!0))+"
\n"}blockquote({tokens:e}){return`
+${this.parser.parse(e)}
+`}html({text:e}){return e}heading({tokens:e,depth:t}){return`${this.parser.parseInline(e)} +`}hr(e){return"
\n"}list(t){var e=t.ordered,n=t.start;let s="";for(let e=0;e\n"+s+"\n"}listitem(e){let t="";var n;return e.task&&(n=this.checkbox({checked:!!e.checked}),e.loose?0${t+=this.parser.parse(e.tokens,!!e.loose)} +`}checkbox({checked:e}){return"'}paragraph({tokens:e}){return`

${this.parser.parseInline(e)}

+`}table(t){var e="";let n="";for(let e=0;e\n\n"+e+"\n"+(s=s&&`${s}`)+"\n"}tablerow({text:e}){return` +${e} +`}tablecell(e){var t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+` +`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${e}`}br(e){return"
"}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){var n=this.parser.parseInline(n),s=o(e);if(null===s)return n;let r='
"}image({href:e,title:t,text:n}){var s=o(e);if(null===s)return n;let r=`${n}{e=o[e].flat(1/0);n=n.concat(this.walkTokens(e,t))}):o.tokens&&(n=n.concat(this.walkTokens(o.tokens,t)))}}return n}use(...e){const w=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(e=>{const t={...e};if(t.async=this.defaults.async||t.async||!1,e.extensions&&(e.extensions.forEach(n=>{if(!n.name)throw new Error("extension name required");if("renderer"in n){const s=w.renderers[n.name];s?w.renderers[n.name]=function(...e){let t=n.renderer.apply(this,e);return t=!1===t?s.apply(this,e):t}:w.renderers[n.name]=n.renderer}if("tokenizer"in n){if(!n.level||"block"!==n.level&&"inline"!==n.level)throw new Error("extension level must be 'block' or 'inline'");const e=w[n.level];e?e.unshift(n.tokenizer):w[n.level]=[n.tokenizer],n.start&&("block"===n.level?w.startBlock?w.startBlock.push(n.start):w.startBlock=[n.start]:"inline"===n.level&&(w.startInline?w.startInline.push(n.start):w.startInline=[n.start]))}"childTokens"in n&&n.childTokens&&(w.childTokens[n.name]=n.childTokens)}),t.extensions=w),e.renderer){const i=this.defaults.renderer||new I(this.defaults);for(const l in e.renderer){if(!(l in i))throw new Error(`renderer '${l}' does not exist`);if(!["options","parser"].includes(l)){var n=l;const a=e.renderer[n],o=i[n];i[n]=(...e)=>{let t=a.apply(i,e);return(t=!1===t?o.apply(i,e):t)||""}}}t.renderer=i}if(e.tokenizer){const c=this.defaults.tokenizer||new m(this.defaults);for(const h in e.tokenizer){if(!(h in c))throw new Error(`tokenizer '${h}' does not exist`);if(!["options","rules","lexer"].includes(h)){var s=h;const p=e.tokenizer[s],u=c[s];c[s]=(...e)=>{let t=p.apply(c,e);return t=!1===t?u.apply(c,e):t}}}t.tokenizer=c}if(e.hooks){const k=this.defaults.hooks||new Z;for(const g in e.hooks){if(!(g in k))throw new Error(`hook '${g}' does not exist`);if(!["options","block"].includes(g)){var r=g;const f=e.hooks[r],d=k[r];Z.passThroughHooks.has(g)?k[r]=e=>{if(this.defaults.async)return Promise.resolve(f.call(k,e)).then(e=>d.call(k,e));e=f.call(k,e);return d.call(k,e)}:k[r]=(...e)=>{let t=f.apply(k,e);return t=!1===t?d.apply(k,e):t}}}t.hooks=k}if(e.walkTokens){const x=this.defaults.walkTokens,b=e.walkTokens;t.walkTokens=function(e){let t=[];return t.push(b.call(this,e)),t=x?t.concat(x.call(this,e)):t}}this.defaults={...this.defaults,...t}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return S.lex(e,t??this.defaults)}parser(e,t){return q.parse(e,t??this.defaults)}parseMarkdown(l){return(n,e)=>{e={...e};const s={...this.defaults,...e},t=this.onError(!!s.silent,!!s.async);if(!0===this.defaults.async&&!1===e.async)return t(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(null==n)return t(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof n)return t(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));s.hooks&&((s.hooks.options=s).hooks.block=l);const r=s.hooks?s.hooks.provideLexer():l?S.lex:S.lexInline,i=s.hooks?s.hooks.provideParser():l?q.parse:q.parseInline;if(s.async)return Promise.resolve(s.hooks?s.hooks.preprocess(n):n).then(e=>r(e,s)).then(e=>s.hooks?s.hooks.processAllTokens(e):e).then(e=>s.walkTokens?Promise.all(this.walkTokens(e,s.walkTokens)).then(()=>e):e).then(e=>i(e,s)).then(e=>s.hooks?s.hooks.postprocess(e):e).catch(t);try{s.hooks&&(n=s.hooks.preprocess(n));let e=r(n,s),t=(s.hooks&&(e=s.hooks.processAllTokens(e)),s.walkTokens&&this.walkTokens(e,s.walkTokens),i(e,s));return t=s.hooks?s.hooks.postprocess(t):t}catch(e){return t(e)}}}onError(n,s){return e=>{var t;if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",n)return t="

An error occurred:

"+l(e.message+"",!0)+"
",s?Promise.resolve(t):t;if(s)return Promise.reject(e);throw e}}}const P=new H;function L(e,t){return P.parse(e,t)}L.options=L.setOptions=function(e){return P.setOptions(e),t(L.defaults=P.defaults),L},L.getDefaults=e,L.defaults=n.defaults,L.use=function(...e){return P.use(...e),t(L.defaults=P.defaults),L},L.walkTokens=function(e,t){return P.walkTokens(e,t)},L.parseInline=P.parseInline,L.Parser=q,L.parser=q.parse,L.Renderer=I,L.TextRenderer=E,L.Lexer=S,L.lexer=S.lex,L.Tokenizer=m,L.Hooks=Z;z=(L.parse=L).options,R=L.setOptions,p=L.use,T=L.walkTokens,d=L.parseInline,w=L,c=q.parse,v=S.lex;n.Hooks=Z,n.Lexer=S,n.Marked=H,n.Parser=q,n.Renderer=I,n.TextRenderer=E,n.Tokenizer=m,n.getDefaults=e,n.lexer=v,n.marked=L,n.options=z,n.parse=w,n.parseInline=d,n.parser=c,n.setOptions=R,n.use=p,n.walkTokens=T}); \ No newline at end of file diff --git a/public/scripts/marked.js b/public/scripts/marked.js new file mode 100644 index 00000000..f76d7d4f --- /dev/null +++ b/public/scripts/marked.js @@ -0,0 +1,2527 @@ +/** + * marked v14.1.3 - a markdown parser + * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed) + * https://github.com/markedjs/marked + */ + +/** + * DO NOT EDIT THIS FILE + * The code in this file is generated from files in ./src/ + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.marked = {})); +})(this, (function (exports) { 'use strict'; + + /** + * Gets the original marked default options. + */ + function _getDefaults() { + return { + async: false, + breaks: false, + extensions: null, + gfm: true, + hooks: null, + pedantic: false, + renderer: null, + silent: false, + tokenizer: null, + walkTokens: null, + }; + } + exports.defaults = _getDefaults(); + function changeDefaults(newDefaults) { + exports.defaults = newDefaults; + } + + /** + * Helpers + */ + const escapeTest = /[&<>"']/; + const escapeReplace = new RegExp(escapeTest.source, 'g'); + const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/; + const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g'); + const escapeReplacements = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + }; + const getEscapeReplacement = (ch) => escapeReplacements[ch]; + function escape$1(html, encode) { + if (encode) { + if (escapeTest.test(html)) { + return html.replace(escapeReplace, getEscapeReplacement); + } + } + else { + if (escapeTestNoEncode.test(html)) { + return html.replace(escapeReplaceNoEncode, getEscapeReplacement); + } + } + return html; + } + const caret = /(^|[^\[])\^/g; + function edit(regex, opt) { + let source = typeof regex === 'string' ? regex : regex.source; + opt = opt || ''; + const obj = { + replace: (name, val) => { + let valSource = typeof val === 'string' ? val : val.source; + valSource = valSource.replace(caret, '$1'); + source = source.replace(name, valSource); + return obj; + }, + getRegex: () => { + return new RegExp(source, opt); + }, + }; + return obj; + } + function cleanUrl(href) { + try { + href = encodeURI(href).replace(/%25/g, '%'); + } + catch { + return null; + } + return href; + } + const noopTest = { exec: () => null }; + function splitCells(tableRow, count) { + // ensure that every cell-delimiting pipe has a space + // before it to distinguish it from an escaped pipe + const row = tableRow.replace(/\|/g, (match, offset, str) => { + let escaped = false; + let curr = offset; + while (--curr >= 0 && str[curr] === '\\') + escaped = !escaped; + if (escaped) { + // odd number of slashes means | is escaped + // so we leave it alone + return '|'; + } + else { + // add space before unescaped | + return ' |'; + } + }), cells = row.split(/ \|/); + let i = 0; + // First/last cell in a row cannot be empty if it has no leading/trailing pipe + if (!cells[0].trim()) { + cells.shift(); + } + if (cells.length > 0 && !cells[cells.length - 1].trim()) { + cells.pop(); + } + if (count) { + if (cells.length > count) { + cells.splice(count); + } + else { + while (cells.length < count) + cells.push(''); + } + } + for (; i < cells.length; i++) { + // leading or trailing whitespace is ignored per the gfm spec + cells[i] = cells[i].trim().replace(/\\\|/g, '|'); + } + return cells; + } + /** + * Remove trailing 'c's. Equivalent to str.replace(/c*$/, ''). + * /c*$/ is vulnerable to REDOS. + * + * @param str + * @param c + * @param invert Remove suffix of non-c chars instead. Default falsey. + */ + function rtrim(str, c, invert) { + const l = str.length; + if (l === 0) { + return ''; + } + // Length of suffix matching the invert condition. + let suffLen = 0; + // Step left until we fail to match the invert condition. + while (suffLen < l) { + const currChar = str.charAt(l - suffLen - 1); + if (currChar === c && !invert) { + suffLen++; + } + else if (currChar !== c && invert) { + suffLen++; + } + else { + break; + } + } + return str.slice(0, l - suffLen); + } + function findClosingBracket(str, b) { + if (str.indexOf(b[1]) === -1) { + return -1; + } + let level = 0; + for (let i = 0; i < str.length; i++) { + if (str[i] === '\\') { + i++; + } + else if (str[i] === b[0]) { + level++; + } + else if (str[i] === b[1]) { + level--; + if (level < 0) { + return i; + } + } + } + return -1; + } + + function outputLink(cap, link, raw, lexer) { + const href = link.href; + const title = link.title ? escape$1(link.title) : null; + const text = cap[1].replace(/\\([\[\]])/g, '$1'); + if (cap[0].charAt(0) !== '!') { + lexer.state.inLink = true; + const token = { + type: 'link', + raw, + href, + title, + text, + tokens: lexer.inlineTokens(text), + }; + lexer.state.inLink = false; + return token; + } + return { + type: 'image', + raw, + href, + title, + text: escape$1(text), + }; + } + function indentCodeCompensation(raw, text) { + const matchIndentToCode = raw.match(/^(\s+)(?:```)/); + if (matchIndentToCode === null) { + return text; + } + const indentToCode = matchIndentToCode[1]; + return text + .split('\n') + .map(node => { + const matchIndentInNode = node.match(/^\s+/); + if (matchIndentInNode === null) { + return node; + } + const [indentInNode] = matchIndentInNode; + if (indentInNode.length >= indentToCode.length) { + return node.slice(indentToCode.length); + } + return node; + }) + .join('\n'); + } + /** + * Tokenizer + */ + class _Tokenizer { + options; + rules; // set by the lexer + lexer; // set by the lexer + constructor(options) { + this.options = options || exports.defaults; + } + space(src) { + const cap = this.rules.block.newline.exec(src); + if (cap && cap[0].length > 0) { + return { + type: 'space', + raw: cap[0], + }; + } + } + code(src) { + const cap = this.rules.block.code.exec(src); + if (cap) { + const text = cap[0].replace(/^(?: {1,4}| {0,3}\t)/gm, ''); + return { + type: 'code', + raw: cap[0], + codeBlockStyle: 'indented', + text: !this.options.pedantic + ? rtrim(text, '\n') + : text, + }; + } + } + fences(src) { + const cap = this.rules.block.fences.exec(src); + if (cap) { + const raw = cap[0]; + const text = indentCodeCompensation(raw, cap[3] || ''); + return { + type: 'code', + raw, + lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2], + text, + }; + } + } + heading(src) { + const cap = this.rules.block.heading.exec(src); + if (cap) { + let text = cap[2].trim(); + // remove trailing #s + if (/#$/.test(text)) { + const trimmed = rtrim(text, '#'); + if (this.options.pedantic) { + text = trimmed.trim(); + } + else if (!trimmed || / $/.test(trimmed)) { + // CommonMark requires space before trailing #s + text = trimmed.trim(); + } + } + return { + type: 'heading', + raw: cap[0], + depth: cap[1].length, + text, + tokens: this.lexer.inline(text), + }; + } + } + hr(src) { + const cap = this.rules.block.hr.exec(src); + if (cap) { + return { + type: 'hr', + raw: rtrim(cap[0], '\n'), + }; + } + } + blockquote(src) { + const cap = this.rules.block.blockquote.exec(src); + if (cap) { + let lines = rtrim(cap[0], '\n').split('\n'); + let raw = ''; + let text = ''; + const tokens = []; + while (lines.length > 0) { + let inBlockquote = false; + const currentLines = []; + let i; + for (i = 0; i < lines.length; i++) { + // get lines up to a continuation + if (/^ {0,3}>/.test(lines[i])) { + currentLines.push(lines[i]); + inBlockquote = true; + } + else if (!inBlockquote) { + currentLines.push(lines[i]); + } + else { + break; + } + } + lines = lines.slice(i); + const currentRaw = currentLines.join('\n'); + const currentText = currentRaw + // precede setext continuation with 4 spaces so it isn't a setext + .replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, '\n $1') + .replace(/^ {0,3}>[ \t]?/gm, ''); + raw = raw ? `${raw}\n${currentRaw}` : currentRaw; + text = text ? `${text}\n${currentText}` : currentText; + // parse blockquote lines as top level tokens + // merge paragraphs if this is a continuation + const top = this.lexer.state.top; + this.lexer.state.top = true; + this.lexer.blockTokens(currentText, tokens, true); + this.lexer.state.top = top; + // if there is no continuation then we are done + if (lines.length === 0) { + break; + } + const lastToken = tokens[tokens.length - 1]; + if (lastToken?.type === 'code') { + // blockquote continuation cannot be preceded by a code block + break; + } + else if (lastToken?.type === 'blockquote') { + // include continuation in nested blockquote + const oldToken = lastToken; + const newText = oldToken.raw + '\n' + lines.join('\n'); + const newToken = this.blockquote(newText); + tokens[tokens.length - 1] = newToken; + raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw; + text = text.substring(0, text.length - oldToken.text.length) + newToken.text; + break; + } + else if (lastToken?.type === 'list') { + // include continuation in nested list + const oldToken = lastToken; + const newText = oldToken.raw + '\n' + lines.join('\n'); + const newToken = this.list(newText); + tokens[tokens.length - 1] = newToken; + raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw; + text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw; + lines = newText.substring(tokens[tokens.length - 1].raw.length).split('\n'); + continue; + } + } + return { + type: 'blockquote', + raw, + tokens, + text, + }; + } + } + list(src) { + let cap = this.rules.block.list.exec(src); + if (cap) { + let bull = cap[1].trim(); + const isordered = bull.length > 1; + const list = { + type: 'list', + raw: '', + ordered: isordered, + start: isordered ? +bull.slice(0, -1) : '', + loose: false, + items: [], + }; + bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`; + if (this.options.pedantic) { + bull = isordered ? bull : '[*+-]'; + } + // Get next list item + const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`); + let endsWithBlankLine = false; + // Check if current bullet point can start a new List Item + while (src) { + let endEarly = false; + let raw = ''; + let itemContents = ''; + if (!(cap = itemRegex.exec(src))) { + break; + } + if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?) + break; + } + raw = cap[0]; + src = src.substring(raw.length); + let line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length)); + let nextLine = src.split('\n', 1)[0]; + let blankLine = !line.trim(); + let indent = 0; + if (this.options.pedantic) { + indent = 2; + itemContents = line.trimStart(); + } + else if (blankLine) { + indent = cap[1].length + 1; + } + else { + indent = cap[2].search(/[^ ]/); // Find first non-space char + indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent + itemContents = line.slice(indent); + indent += cap[1].length; + } + if (blankLine && /^[ \t]*$/.test(nextLine)) { // Items begin with at most one blank line + raw += nextLine + '\n'; + src = src.substring(nextLine.length + 1); + endEarly = true; + } + if (!endEarly) { + const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`); + const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`); + const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`); + const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`); + const htmlBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}<[a-z].*>`, 'i'); + // Check if following lines should be included in List Item + while (src) { + const rawLine = src.split('\n', 1)[0]; + let nextLineWithoutTabs; + nextLine = rawLine; + // Re-align to follow commonmark nesting rules + if (this.options.pedantic) { + nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' '); + nextLineWithoutTabs = nextLine; + } + else { + nextLineWithoutTabs = nextLine.replace(/\t/g, ' '); + } + // End list item if found code fences + if (fencesBeginRegex.test(nextLine)) { + break; + } + // End list item if found start of new heading + if (headingBeginRegex.test(nextLine)) { + break; + } + // End list item if found start of html block + if (htmlBeginRegex.test(nextLine)) { + break; + } + // End list item if found start of new bullet + if (nextBulletRegex.test(nextLine)) { + break; + } + // Horizontal rule found + if (hrRegex.test(nextLine)) { + break; + } + if (nextLineWithoutTabs.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible + itemContents += '\n' + nextLineWithoutTabs.slice(indent); + } + else { + // not enough indentation + if (blankLine) { + break; + } + // paragraph continuation unless last line was a different block level element + if (line.replace(/\t/g, ' ').search(/[^ ]/) >= 4) { // indented code block + break; + } + if (fencesBeginRegex.test(line)) { + break; + } + if (headingBeginRegex.test(line)) { + break; + } + if (hrRegex.test(line)) { + break; + } + itemContents += '\n' + nextLine; + } + if (!blankLine && !nextLine.trim()) { // Check if current line is blank + blankLine = true; + } + raw += rawLine + '\n'; + src = src.substring(rawLine.length + 1); + line = nextLineWithoutTabs.slice(indent); + } + } + if (!list.loose) { + // If the previous item ended with a blank line, the list is loose + if (endsWithBlankLine) { + list.loose = true; + } + else if (/\n[ \t]*\n[ \t]*$/.test(raw)) { + endsWithBlankLine = true; + } + } + let istask = null; + let ischecked; + // Check for task list items + if (this.options.gfm) { + istask = /^\[[ xX]\] /.exec(itemContents); + if (istask) { + ischecked = istask[0] !== '[ ] '; + itemContents = itemContents.replace(/^\[[ xX]\] +/, ''); + } + } + list.items.push({ + type: 'list_item', + raw, + task: !!istask, + checked: ischecked, + loose: false, + text: itemContents, + tokens: [], + }); + list.raw += raw; + } + // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic + list.items[list.items.length - 1].raw = list.items[list.items.length - 1].raw.trimEnd(); + list.items[list.items.length - 1].text = list.items[list.items.length - 1].text.trimEnd(); + list.raw = list.raw.trimEnd(); + // Item child tokens handled here at end because we needed to have the final item to trim it first + for (let i = 0; i < list.items.length; i++) { + this.lexer.state.top = false; + list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []); + if (!list.loose) { + // Check if list should be loose + const spacers = list.items[i].tokens.filter(t => t.type === 'space'); + const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\n.*\n/.test(t.raw)); + list.loose = hasMultipleLineBreaks; + } + } + // Set all items to loose if list is loose + if (list.loose) { + for (let i = 0; i < list.items.length; i++) { + list.items[i].loose = true; + } + } + return list; + } + } + html(src) { + const cap = this.rules.block.html.exec(src); + if (cap) { + const token = { + type: 'html', + block: true, + raw: cap[0], + pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style', + text: cap[0], + }; + return token; + } + } + def(src) { + const cap = this.rules.block.def.exec(src); + if (cap) { + const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : ''; + const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3]; + return { + type: 'def', + tag, + raw: cap[0], + href, + title, + }; + } + } + table(src) { + const cap = this.rules.block.table.exec(src); + if (!cap) { + return; + } + if (!/[:|]/.test(cap[2])) { + // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading + return; + } + const headers = splitCells(cap[1]); + const aligns = cap[2].replace(/^\||\| *$/g, '').split('|'); + const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : []; + const item = { + type: 'table', + raw: cap[0], + header: [], + align: [], + rows: [], + }; + if (headers.length !== aligns.length) { + // header and align columns must be equal, rows can be different. + return; + } + for (const align of aligns) { + if (/^ *-+: *$/.test(align)) { + item.align.push('right'); + } + else if (/^ *:-+: *$/.test(align)) { + item.align.push('center'); + } + else if (/^ *:-+ *$/.test(align)) { + item.align.push('left'); + } + else { + item.align.push(null); + } + } + for (let i = 0; i < headers.length; i++) { + item.header.push({ + text: headers[i], + tokens: this.lexer.inline(headers[i]), + header: true, + align: item.align[i], + }); + } + for (const row of rows) { + item.rows.push(splitCells(row, item.header.length).map((cell, i) => { + return { + text: cell, + tokens: this.lexer.inline(cell), + header: false, + align: item.align[i], + }; + })); + } + return item; + } + lheading(src) { + const cap = this.rules.block.lheading.exec(src); + if (cap) { + return { + type: 'heading', + raw: cap[0], + depth: cap[2].charAt(0) === '=' ? 1 : 2, + text: cap[1], + tokens: this.lexer.inline(cap[1]), + }; + } + } + paragraph(src) { + const cap = this.rules.block.paragraph.exec(src); + if (cap) { + const text = cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1]; + return { + type: 'paragraph', + raw: cap[0], + text, + tokens: this.lexer.inline(text), + }; + } + } + text(src) { + const cap = this.rules.block.text.exec(src); + if (cap) { + return { + type: 'text', + raw: cap[0], + text: cap[0], + tokens: this.lexer.inline(cap[0]), + }; + } + } + escape(src) { + const cap = this.rules.inline.escape.exec(src); + if (cap) { + return { + type: 'escape', + raw: cap[0], + text: escape$1(cap[1]), + }; + } + } + tag(src) { + const cap = this.rules.inline.tag.exec(src); + if (cap) { + if (!this.lexer.state.inLink && /^
/i.test(cap[0])) { + this.lexer.state.inLink = false; + } + if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.lexer.state.inRawBlock = true; + } + else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.lexer.state.inRawBlock = false; + } + return { + type: 'html', + raw: cap[0], + inLink: this.lexer.state.inLink, + inRawBlock: this.lexer.state.inRawBlock, + block: false, + text: cap[0], + }; + } + } + link(src) { + const cap = this.rules.inline.link.exec(src); + if (cap) { + const trimmedUrl = cap[2].trim(); + if (!this.options.pedantic && /^$/.test(trimmedUrl))) { + return; + } + // ending angle bracket cannot be escaped + const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\'); + if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) { + return; + } + } + else { + // find closing parenthesis + const lastParenIndex = findClosingBracket(cap[2], '()'); + if (lastParenIndex > -1) { + const start = cap[0].indexOf('!') === 0 ? 5 : 4; + const linkLen = start + cap[1].length + lastParenIndex; + cap[2] = cap[2].substring(0, lastParenIndex); + cap[0] = cap[0].substring(0, linkLen).trim(); + cap[3] = ''; + } + } + let href = cap[2]; + let title = ''; + if (this.options.pedantic) { + // split pedantic href and title + const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + if (link) { + href = link[1]; + title = link[3]; + } + } + else { + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + href = href.trim(); + if (/^$/.test(trimmedUrl))) { + // pedantic allows starting angle bracket without ending angle bracket + href = href.slice(1); + } + else { + href = href.slice(1, -1); + } + } + return outputLink(cap, { + href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href, + title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title, + }, cap[0], this.lexer); + } + } + reflink(src, links) { + let cap; + if ((cap = this.rules.inline.reflink.exec(src)) + || (cap = this.rules.inline.nolink.exec(src))) { + const linkString = (cap[2] || cap[1]).replace(/\s+/g, ' '); + const link = links[linkString.toLowerCase()]; + if (!link) { + const text = cap[0].charAt(0); + return { + type: 'text', + raw: text, + text, + }; + } + return outputLink(cap, link, cap[0], this.lexer); + } + } + emStrong(src, maskedSrc, prevChar = '') { + let match = this.rules.inline.emStrongLDelim.exec(src); + if (!match) + return; + // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well + if (match[3] && prevChar.match(/[\p{L}\p{N}]/u)) + return; + const nextChar = match[1] || match[2] || ''; + if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) { + // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below) + const lLength = [...match[0]].length - 1; + let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0; + const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd; + endReg.lastIndex = 0; + // Clip maskedSrc to same section of string as src (move to lexer?) + maskedSrc = maskedSrc.slice(-1 * src.length + lLength); + while ((match = endReg.exec(maskedSrc)) != null) { + rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6]; + if (!rDelim) + continue; // skip single * in __abc*abc__ + rLength = [...rDelim].length; + if (match[3] || match[4]) { // found another Left Delim + delimTotal += rLength; + continue; + } + else if (match[5] || match[6]) { // either Left or Right Delim + if (lLength % 3 && !((lLength + rLength) % 3)) { + midDelimTotal += rLength; + continue; // CommonMark Emphasis Rules 9-10 + } + } + delimTotal -= rLength; + if (delimTotal > 0) + continue; // Haven't found enough closing delimiters + // Remove extra characters. *a*** -> *a* + rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); + // char length can be >1 for unicode characters; + const lastCharLength = [...match[0]][0].length; + const raw = src.slice(0, lLength + match.index + lastCharLength + rLength); + // Create `em` if smallest delimiter has odd char count. *a*** + if (Math.min(lLength, rLength) % 2) { + const text = raw.slice(1, -1); + return { + type: 'em', + raw, + text, + tokens: this.lexer.inlineTokens(text), + }; + } + // Create 'strong' if smallest delimiter has even char count. **a*** + const text = raw.slice(2, -2); + return { + type: 'strong', + raw, + text, + tokens: this.lexer.inlineTokens(text), + }; + } + } + } + codespan(src) { + const cap = this.rules.inline.code.exec(src); + if (cap) { + let text = cap[2].replace(/\n/g, ' '); + const hasNonSpaceChars = /[^ ]/.test(text); + const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text); + if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) { + text = text.substring(1, text.length - 1); + } + text = escape$1(text, true); + return { + type: 'codespan', + raw: cap[0], + text, + }; + } + } + br(src) { + const cap = this.rules.inline.br.exec(src); + if (cap) { + return { + type: 'br', + raw: cap[0], + }; + } + } + del(src) { + const cap = this.rules.inline.del.exec(src); + if (cap) { + return { + type: 'del', + raw: cap[0], + text: cap[2], + tokens: this.lexer.inlineTokens(cap[2]), + }; + } + } + autolink(src) { + const cap = this.rules.inline.autolink.exec(src); + if (cap) { + let text, href; + if (cap[2] === '@') { + text = escape$1(cap[1]); + href = 'mailto:' + text; + } + else { + text = escape$1(cap[1]); + href = text; + } + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text, + }, + ], + }; + } + } + url(src) { + let cap; + if (cap = this.rules.inline.url.exec(src)) { + let text, href; + if (cap[2] === '@') { + text = escape$1(cap[0]); + href = 'mailto:' + text; + } + else { + // do extended autolink path validation + let prevCapZero; + do { + prevCapZero = cap[0]; + cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? ''; + } while (prevCapZero !== cap[0]); + text = escape$1(cap[0]); + if (cap[1] === 'www.') { + href = 'http://' + cap[0]; + } + else { + href = cap[0]; + } + } + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text, + }, + ], + }; + } + } + inlineText(src) { + const cap = this.rules.inline.text.exec(src); + if (cap) { + let text; + if (this.lexer.state.inRawBlock) { + text = cap[0]; + } + else { + text = escape$1(cap[0]); + } + return { + type: 'text', + raw: cap[0], + text, + }; + } + } + } + + /** + * Block-Level Grammar + */ + const newline = /^(?:[ \t]*(?:\n|$))+/; + const blockCode = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/; + const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/; + const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/; + const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/; + const bullet = /(?:[*+-]|\d{1,9}[.)])/; + const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/) + .replace(/bull/g, bullet) // lists can interrupt + .replace(/blockCode/g, /(?: {4}| {0,3}\t)/) // indented code blocks can interrupt + .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt + .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt + .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt + .replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt + .getRegex(); + const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/; + const blockText = /^[^\n]+/; + const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/; + const def = edit(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/) + .replace('label', _blockLabel) + .replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/) + .getRegex(); + const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/) + .replace(/bull/g, bullet) + .getRegex(); + const _tag = 'address|article|aside|base|basefont|blockquote|body|caption' + + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title' + + '|tr|track|ul'; + const _comment = /|$))/; + const html = edit('^ {0,3}(?:' // optional indentation + + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) + + '|comment[^\\n]*(\\n+|$)' // (2) + + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3) + + '|\\n*|$)' // (4) + + '|\\n*|$)' // (5) + + '|)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (6) + + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (7) open tag + + '|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)' // (7) closing tag + + ')', 'i') + .replace('comment', _comment) + .replace('tag', _tag) + .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/) + .getRegex(); + const paragraph = edit(_paragraph) + .replace('hr', hr) + .replace('heading', ' {0,3}#{1,6}(?:\\s|$)') + .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs + .replace('|table', '') + .replace('blockquote', ' {0,3}>') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', _tag) // pars can be interrupted by type (6) html blocks + .getRegex(); + const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/) + .replace('paragraph', paragraph) + .getRegex(); + /** + * Normal Block Grammar + */ + const blockNormal = { + blockquote, + code: blockCode, + def, + fences, + heading, + hr, + html, + lheading, + list, + newline, + paragraph, + table: noopTest, + text: blockText, + }; + /** + * GFM Block Grammar + */ + const gfmTable = edit('^ *([^\\n ].*)\\n' // Header + + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align + + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells + .replace('hr', hr) + .replace('heading', ' {0,3}#{1,6}(?:\\s|$)') + .replace('blockquote', ' {0,3}>') + .replace('code', '(?: {4}| {0,3}\t)[^\\n]') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', _tag) // tables can be interrupted by type (6) html blocks + .getRegex(); + const blockGfm = { + ...blockNormal, + table: gfmTable, + paragraph: edit(_paragraph) + .replace('hr', hr) + .replace('heading', ' {0,3}#{1,6}(?:\\s|$)') + .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs + .replace('table', gfmTable) // interrupt paragraphs with table + .replace('blockquote', ' {0,3}>') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', _tag) // pars can be interrupted by type (6) html blocks + .getRegex(), + }; + /** + * Pedantic grammar (original John Gruber's loose markdown specification) + */ + const blockPedantic = { + ...blockNormal, + html: edit('^ *(?:comment *(?:\\n|\\s*$)' + + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag + + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))') + .replace('comment', _comment) + .replace(/tag/g, '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b') + .getRegex(), + def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, + heading: /^(#{1,6})(.*)(?:\n+|$)/, + fences: noopTest, // fences not supported + lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, + paragraph: edit(_paragraph) + .replace('hr', hr) + .replace('heading', ' *#{1,6} *[^\n]') + .replace('lheading', lheading) + .replace('|table', '') + .replace('blockquote', ' {0,3}>') + .replace('|fences', '') + .replace('|list', '') + .replace('|html', '') + .replace('|tag', '') + .getRegex(), + }; + /** + * Inline-Level Grammar + */ + const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/; + const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/; + const br = /^( {2,}|\\)\n(?!\s*$)/; + const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\ + const blockSkip = /\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g; + const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u') + .replace(/punct/g, _punctuation) + .getRegex(); + const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong + + '|[^*]+(?=[^*])' // Consume to delim + + '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter + + '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter + + '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter + + '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter + + '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter + + '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter + .replace(/punct/g, _punctuation) + .getRegex(); + // (6) Not allowed for _ + const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong + + '|[^_]+(?=[^_])' // Consume to delim + + '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter + + '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter + + '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter + + '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter + + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter + .replace(/punct/g, _punctuation) + .getRegex(); + const anyPunctuation = edit(/\\([punct])/, 'gu') + .replace(/punct/g, _punctuation) + .getRegex(); + const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/) + .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/) + .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/) + .getRegex(); + const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex(); + const tag = edit('^comment' + + '|^' // self-closing tag + + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag + + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. + + '|^' // declaration, e.g. + + '|^') // CDATA section + .replace('comment', _inlineComment) + .replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/) + .getRegex(); + const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; + const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/) + .replace('label', _inlineLabel) + .replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/) + .replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/) + .getRegex(); + const reflink = edit(/^!?\[(label)\]\[(ref)\]/) + .replace('label', _inlineLabel) + .replace('ref', _blockLabel) + .getRegex(); + const nolink = edit(/^!?\[(ref)\](?:\[\])?/) + .replace('ref', _blockLabel) + .getRegex(); + const reflinkSearch = edit('reflink|nolink(?!\\()', 'g') + .replace('reflink', reflink) + .replace('nolink', nolink) + .getRegex(); + /** + * Normal Inline Grammar + */ + const inlineNormal = { + _backpedal: noopTest, // only used for GFM url + anyPunctuation, + autolink, + blockSkip, + br, + code: inlineCode, + del: noopTest, + emStrongLDelim, + emStrongRDelimAst, + emStrongRDelimUnd, + escape, + link, + nolink, + punctuation, + reflink, + reflinkSearch, + tag, + text: inlineText, + url: noopTest, + }; + /** + * Pedantic Inline Grammar + */ + const inlinePedantic = { + ...inlineNormal, + link: edit(/^!?\[(label)\]\((.*?)\)/) + .replace('label', _inlineLabel) + .getRegex(), + reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/) + .replace('label', _inlineLabel) + .getRegex(), + }; + /** + * GFM Inline Grammar + */ + const inlineGfm = { + ...inlineNormal, + escape: edit(escape).replace('])', '~|])').getRegex(), + url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i') + .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/) + .getRegex(), + _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, + del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/, + text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\ { + if (token = extTokenizer.call({ lexer: this }, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); + return true; + } + return false; + })) { + continue; + } + // newline + if (token = this.tokenizer.space(src)) { + src = src.substring(token.raw.length); + if (token.raw.length === 1 && tokens.length > 0) { + // if there's a single \n as a spacer, it's terminating the last line, + // so move it there so that we don't get unnecessary paragraph tags + tokens[tokens.length - 1].raw += '\n'; + } + else { + tokens.push(token); + } + continue; + } + // code + if (token = this.tokenizer.code(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + // An indented code block cannot interrupt a paragraph. + if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.text; + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else { + tokens.push(token); + } + continue; + } + // fences + if (token = this.tokenizer.fences(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // heading + if (token = this.tokenizer.heading(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // hr + if (token = this.tokenizer.hr(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // blockquote + if (token = this.tokenizer.blockquote(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // list + if (token = this.tokenizer.list(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // html + if (token = this.tokenizer.html(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // def + if (token = this.tokenizer.def(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.raw; + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else if (!this.tokens.links[token.tag]) { + this.tokens.links[token.tag] = { + href: token.href, + title: token.title, + }; + } + continue; + } + // table (gfm) + if (token = this.tokenizer.table(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // lheading + if (token = this.tokenizer.lheading(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // top-level paragraph + // prevent paragraph consuming extensions by clipping 'src' to extension start + cutSrc = src; + if (this.options.extensions && this.options.extensions.startBlock) { + let startIndex = Infinity; + const tempSrc = src.slice(1); + let tempStart; + this.options.extensions.startBlock.forEach((getStartIndex) => { + tempStart = getStartIndex.call({ lexer: this }, tempSrc); + if (typeof tempStart === 'number' && tempStart >= 0) { + startIndex = Math.min(startIndex, tempStart); + } + }); + if (startIndex < Infinity && startIndex >= 0) { + cutSrc = src.substring(0, startIndex + 1); + } + } + if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) { + lastToken = tokens[tokens.length - 1]; + if (lastParagraphClipped && lastToken?.type === 'paragraph') { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.text; + this.inlineQueue.pop(); + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else { + tokens.push(token); + } + lastParagraphClipped = (cutSrc.length !== src.length); + src = src.substring(token.raw.length); + continue; + } + // text + if (token = this.tokenizer.text(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && lastToken.type === 'text') { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.text; + this.inlineQueue.pop(); + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else { + tokens.push(token); + } + continue; + } + if (src) { + const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (this.options.silent) { + console.error(errMsg); + break; + } + else { + throw new Error(errMsg); + } + } + } + this.state.top = true; + return tokens; + } + inline(src, tokens = []) { + this.inlineQueue.push({ src, tokens }); + return tokens; + } + /** + * Lexing/Compiling + */ + inlineTokens(src, tokens = []) { + let token, lastToken, cutSrc; + // String with links masked to avoid interference with em and strong + let maskedSrc = src; + let match; + let keepPrevChar, prevChar; + // Mask out reflinks + if (this.tokens.links) { + const links = Object.keys(this.tokens.links); + if (links.length > 0) { + while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) { + if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) { + maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex); + } + } + } + } + // Mask out other blocks + while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) { + maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex); + } + // Mask out escaped characters + while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) { + maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex); + } + while (src) { + if (!keepPrevChar) { + prevChar = ''; + } + keepPrevChar = false; + // extensions + if (this.options.extensions + && this.options.extensions.inline + && this.options.extensions.inline.some((extTokenizer) => { + if (token = extTokenizer.call({ lexer: this }, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); + return true; + } + return false; + })) { + continue; + } + // escape + if (token = this.tokenizer.escape(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // tag + if (token = this.tokenizer.tag(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && token.type === 'text' && lastToken.type === 'text') { + lastToken.raw += token.raw; + lastToken.text += token.text; + } + else { + tokens.push(token); + } + continue; + } + // link + if (token = this.tokenizer.link(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // reflink, nolink + if (token = this.tokenizer.reflink(src, this.tokens.links)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && token.type === 'text' && lastToken.type === 'text') { + lastToken.raw += token.raw; + lastToken.text += token.text; + } + else { + tokens.push(token); + } + continue; + } + // em & strong + if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // code + if (token = this.tokenizer.codespan(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // br + if (token = this.tokenizer.br(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // del (gfm) + if (token = this.tokenizer.del(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // autolink + if (token = this.tokenizer.autolink(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // url (gfm) + if (!this.state.inLink && (token = this.tokenizer.url(src))) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // text + // prevent inlineText consuming extensions by clipping 'src' to extension start + cutSrc = src; + if (this.options.extensions && this.options.extensions.startInline) { + let startIndex = Infinity; + const tempSrc = src.slice(1); + let tempStart; + this.options.extensions.startInline.forEach((getStartIndex) => { + tempStart = getStartIndex.call({ lexer: this }, tempSrc); + if (typeof tempStart === 'number' && tempStart >= 0) { + startIndex = Math.min(startIndex, tempStart); + } + }); + if (startIndex < Infinity && startIndex >= 0) { + cutSrc = src.substring(0, startIndex + 1); + } + } + if (token = this.tokenizer.inlineText(cutSrc)) { + src = src.substring(token.raw.length); + if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started + prevChar = token.raw.slice(-1); + } + keepPrevChar = true; + lastToken = tokens[tokens.length - 1]; + if (lastToken && lastToken.type === 'text') { + lastToken.raw += token.raw; + lastToken.text += token.text; + } + else { + tokens.push(token); + } + continue; + } + if (src) { + const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (this.options.silent) { + console.error(errMsg); + break; + } + else { + throw new Error(errMsg); + } + } + } + return tokens; + } + } + + /** + * Renderer + */ + class _Renderer { + options; + parser; // set by the parser + constructor(options) { + this.options = options || exports.defaults; + } + space(token) { + return ''; + } + code({ text, lang, escaped }) { + const langString = (lang || '').match(/^\S*/)?.[0]; + const code = text.replace(/\n$/, '') + '\n'; + if (!langString) { + return '
'
+                    + (escaped ? code : escape$1(code, true))
+                    + '
\n'; + } + return '
'
+                + (escaped ? code : escape$1(code, true))
+                + '
\n'; + } + blockquote({ tokens }) { + const body = this.parser.parse(tokens); + return `
\n${body}
\n`; + } + html({ text }) { + return text; + } + heading({ tokens, depth }) { + return `${this.parser.parseInline(tokens)}\n`; + } + hr(token) { + return '
\n'; + } + list(token) { + const ordered = token.ordered; + const start = token.start; + let body = ''; + for (let j = 0; j < token.items.length; j++) { + const item = token.items[j]; + body += this.listitem(item); + } + const type = ordered ? 'ol' : 'ul'; + const startAttr = (ordered && start !== 1) ? (' start="' + start + '"') : ''; + return '<' + type + startAttr + '>\n' + body + '\n'; + } + listitem(item) { + let itemBody = ''; + if (item.task) { + const checkbox = this.checkbox({ checked: !!item.checked }); + if (item.loose) { + if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') { + item.tokens[0].text = checkbox + ' ' + item.tokens[0].text; + if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') { + item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text; + } + } + else { + item.tokens.unshift({ + type: 'text', + raw: checkbox + ' ', + text: checkbox + ' ', + }); + } + } + else { + itemBody += checkbox + ' '; + } + } + itemBody += this.parser.parse(item.tokens, !!item.loose); + return `
  • ${itemBody}
  • \n`; + } + checkbox({ checked }) { + return ''; + } + paragraph({ tokens }) { + return `

    ${this.parser.parseInline(tokens)}

    \n`; + } + table(token) { + let header = ''; + // header + let cell = ''; + for (let j = 0; j < token.header.length; j++) { + cell += this.tablecell(token.header[j]); + } + header += this.tablerow({ text: cell }); + let body = ''; + for (let j = 0; j < token.rows.length; j++) { + const row = token.rows[j]; + cell = ''; + for (let k = 0; k < row.length; k++) { + cell += this.tablecell(row[k]); + } + body += this.tablerow({ text: cell }); + } + if (body) + body = `${body}`; + return '\n' + + '\n' + + header + + '\n' + + body + + '
    \n'; + } + tablerow({ text }) { + return `\n${text}\n`; + } + tablecell(token) { + const content = this.parser.parseInline(token.tokens); + const type = token.header ? 'th' : 'td'; + const tag = token.align + ? `<${type} align="${token.align}">` + : `<${type}>`; + return tag + content + `\n`; + } + /** + * span level renderer + */ + strong({ tokens }) { + return `${this.parser.parseInline(tokens)}`; + } + em({ tokens }) { + return `${this.parser.parseInline(tokens)}`; + } + codespan({ text }) { + return `${text}`; + } + br(token) { + return '
    '; + } + del({ tokens }) { + return `${this.parser.parseInline(tokens)}`; + } + link({ href, title, tokens }) { + const text = this.parser.parseInline(tokens); + const cleanHref = cleanUrl(href); + if (cleanHref === null) { + return text; + } + href = cleanHref; + let out = '
    '; + return out; + } + image({ href, title, text }) { + const cleanHref = cleanUrl(href); + if (cleanHref === null) { + return text; + } + href = cleanHref; + let out = `${text} { + const tokens = genericToken[childTokens].flat(Infinity); + values = values.concat(this.walkTokens(tokens, callback)); + }); + } + else if (genericToken.tokens) { + values = values.concat(this.walkTokens(genericToken.tokens, callback)); + } + } + } + } + return values; + } + use(...args) { + const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} }; + args.forEach((pack) => { + // copy options to new object + const opts = { ...pack }; + // set async to true if it was set to true before + opts.async = this.defaults.async || opts.async || false; + // ==-- Parse "addon" extensions --== // + if (pack.extensions) { + pack.extensions.forEach((ext) => { + if (!ext.name) { + throw new Error('extension name required'); + } + if ('renderer' in ext) { // Renderer extensions + const prevRenderer = extensions.renderers[ext.name]; + if (prevRenderer) { + // Replace extension with func to run new extension but fall back if false + extensions.renderers[ext.name] = function (...args) { + let ret = ext.renderer.apply(this, args); + if (ret === false) { + ret = prevRenderer.apply(this, args); + } + return ret; + }; + } + else { + extensions.renderers[ext.name] = ext.renderer; + } + } + if ('tokenizer' in ext) { // Tokenizer Extensions + if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) { + throw new Error("extension level must be 'block' or 'inline'"); + } + const extLevel = extensions[ext.level]; + if (extLevel) { + extLevel.unshift(ext.tokenizer); + } + else { + extensions[ext.level] = [ext.tokenizer]; + } + if (ext.start) { // Function to check for start of token + if (ext.level === 'block') { + if (extensions.startBlock) { + extensions.startBlock.push(ext.start); + } + else { + extensions.startBlock = [ext.start]; + } + } + else if (ext.level === 'inline') { + if (extensions.startInline) { + extensions.startInline.push(ext.start); + } + else { + extensions.startInline = [ext.start]; + } + } + } + } + if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens + extensions.childTokens[ext.name] = ext.childTokens; + } + }); + opts.extensions = extensions; + } + // ==-- Parse "overwrite" extensions --== // + if (pack.renderer) { + const renderer = this.defaults.renderer || new _Renderer(this.defaults); + for (const prop in pack.renderer) { + if (!(prop in renderer)) { + throw new Error(`renderer '${prop}' does not exist`); + } + if (['options', 'parser'].includes(prop)) { + // ignore options property + continue; + } + const rendererProp = prop; + const rendererFunc = pack.renderer[rendererProp]; + const prevRenderer = renderer[rendererProp]; + // Replace renderer with func to run extension, but fall back if false + renderer[rendererProp] = (...args) => { + let ret = rendererFunc.apply(renderer, args); + if (ret === false) { + ret = prevRenderer.apply(renderer, args); + } + return ret || ''; + }; + } + opts.renderer = renderer; + } + if (pack.tokenizer) { + const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults); + for (const prop in pack.tokenizer) { + if (!(prop in tokenizer)) { + throw new Error(`tokenizer '${prop}' does not exist`); + } + if (['options', 'rules', 'lexer'].includes(prop)) { + // ignore options, rules, and lexer properties + continue; + } + const tokenizerProp = prop; + const tokenizerFunc = pack.tokenizer[tokenizerProp]; + const prevTokenizer = tokenizer[tokenizerProp]; + // Replace tokenizer with func to run extension, but fall back if false + // @ts-expect-error cannot type tokenizer function dynamically + tokenizer[tokenizerProp] = (...args) => { + let ret = tokenizerFunc.apply(tokenizer, args); + if (ret === false) { + ret = prevTokenizer.apply(tokenizer, args); + } + return ret; + }; + } + opts.tokenizer = tokenizer; + } + // ==-- Parse Hooks extensions --== // + if (pack.hooks) { + const hooks = this.defaults.hooks || new _Hooks(); + for (const prop in pack.hooks) { + if (!(prop in hooks)) { + throw new Error(`hook '${prop}' does not exist`); + } + if (['options', 'block'].includes(prop)) { + // ignore options and block properties + continue; + } + const hooksProp = prop; + const hooksFunc = pack.hooks[hooksProp]; + const prevHook = hooks[hooksProp]; + if (_Hooks.passThroughHooks.has(prop)) { + // @ts-expect-error cannot type hook function dynamically + hooks[hooksProp] = (arg) => { + if (this.defaults.async) { + return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => { + return prevHook.call(hooks, ret); + }); + } + const ret = hooksFunc.call(hooks, arg); + return prevHook.call(hooks, ret); + }; + } + else { + // @ts-expect-error cannot type hook function dynamically + hooks[hooksProp] = (...args) => { + let ret = hooksFunc.apply(hooks, args); + if (ret === false) { + ret = prevHook.apply(hooks, args); + } + return ret; + }; + } + } + opts.hooks = hooks; + } + // ==-- Parse WalkTokens extensions --== // + if (pack.walkTokens) { + const walkTokens = this.defaults.walkTokens; + const packWalktokens = pack.walkTokens; + opts.walkTokens = function (token) { + let values = []; + values.push(packWalktokens.call(this, token)); + if (walkTokens) { + values = values.concat(walkTokens.call(this, token)); + } + return values; + }; + } + this.defaults = { ...this.defaults, ...opts }; + }); + return this; + } + setOptions(opt) { + this.defaults = { ...this.defaults, ...opt }; + return this; + } + lexer(src, options) { + return _Lexer.lex(src, options ?? this.defaults); + } + parser(tokens, options) { + return _Parser.parse(tokens, options ?? this.defaults); + } + parseMarkdown(blockType) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const parse = (src, options) => { + const origOpt = { ...options }; + const opt = { ...this.defaults, ...origOpt }; + const throwError = this.onError(!!opt.silent, !!opt.async); + // throw error if an extension set async to true but parse was called with async: false + if (this.defaults.async === true && origOpt.async === false) { + return throwError(new Error('marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.')); + } + // throw error in case of non string input + if (typeof src === 'undefined' || src === null) { + return throwError(new Error('marked(): input parameter is undefined or null')); + } + if (typeof src !== 'string') { + return throwError(new Error('marked(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected')); + } + if (opt.hooks) { + opt.hooks.options = opt; + opt.hooks.block = blockType; + } + const lexer = opt.hooks ? opt.hooks.provideLexer() : (blockType ? _Lexer.lex : _Lexer.lexInline); + const parser = opt.hooks ? opt.hooks.provideParser() : (blockType ? _Parser.parse : _Parser.parseInline); + if (opt.async) { + return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src) + .then(src => lexer(src, opt)) + .then(tokens => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens) + .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens) + .then(tokens => parser(tokens, opt)) + .then(html => opt.hooks ? opt.hooks.postprocess(html) : html) + .catch(throwError); + } + try { + if (opt.hooks) { + src = opt.hooks.preprocess(src); + } + let tokens = lexer(src, opt); + if (opt.hooks) { + tokens = opt.hooks.processAllTokens(tokens); + } + if (opt.walkTokens) { + this.walkTokens(tokens, opt.walkTokens); + } + let html = parser(tokens, opt); + if (opt.hooks) { + html = opt.hooks.postprocess(html); + } + return html; + } + catch (e) { + return throwError(e); + } + }; + return parse; + } + onError(silent, async) { + return (e) => { + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; + if (silent) { + const msg = '

    An error occurred:

    '
    +                        + escape$1(e.message + '', true)
    +                        + '
    '; + if (async) { + return Promise.resolve(msg); + } + return msg; + } + if (async) { + return Promise.reject(e); + } + throw e; + }; + } + } + + const markedInstance = new Marked(); + function marked(src, opt) { + return markedInstance.parse(src, opt); + } + /** + * Sets the default options. + * + * @param options Hash of options + */ + marked.options = + marked.setOptions = function (options) { + markedInstance.setOptions(options); + marked.defaults = markedInstance.defaults; + changeDefaults(marked.defaults); + return marked; + }; + /** + * Gets the original marked default options. + */ + marked.getDefaults = _getDefaults; + marked.defaults = exports.defaults; + /** + * Use Extension + */ + marked.use = function (...args) { + markedInstance.use(...args); + marked.defaults = markedInstance.defaults; + changeDefaults(marked.defaults); + return marked; + }; + /** + * Run callback for every token + */ + marked.walkTokens = function (tokens, callback) { + return markedInstance.walkTokens(tokens, callback); + }; + /** + * Compiles markdown to HTML without enclosing `p` tag. + * + * @param src String of markdown source to be compiled + * @param options Hash of options + * @return String of compiled HTML + */ + marked.parseInline = markedInstance.parseInline; + /** + * Expose + */ + marked.Parser = _Parser; + marked.parser = _Parser.parse; + marked.Renderer = _Renderer; + marked.TextRenderer = _TextRenderer; + marked.Lexer = _Lexer; + marked.lexer = _Lexer.lex; + marked.Tokenizer = _Tokenizer; + marked.Hooks = _Hooks; + marked.parse = marked; + const options = marked.options; + const setOptions = marked.setOptions; + const use = marked.use; + const walkTokens = marked.walkTokens; + const parseInline = marked.parseInline; + const parse = marked; + const parser = _Parser.parse; + const lexer = _Lexer.lex; + + exports.Hooks = _Hooks; + exports.Lexer = _Lexer; + exports.Marked = Marked; + exports.Parser = _Parser; + exports.Renderer = _Renderer; + exports.TextRenderer = _TextRenderer; + exports.Tokenizer = _Tokenizer; + exports.getDefaults = _getDefaults; + exports.lexer = lexer; + exports.marked = marked; + exports.options = options; + exports.parse = parse; + exports.parseInline = parseInline; + exports.parser = parser; + exports.setOptions = setOptions; + exports.use = use; + exports.walkTokens = walkTokens; + +})); +//# sourceMappingURL=marked.umd.js.map diff --git a/public/scripts/marked.umd.js.map b/public/scripts/marked.umd.js.map new file mode 100644 index 00000000..ebd5196a --- /dev/null +++ b/public/scripts/marked.umd.js.map @@ -0,0 +1 @@ +{"version":3,"file":"marked.umd.js","sources":["../src/defaults.ts","../src/helpers.ts","../src/Tokenizer.ts","../src/rules.ts","../src/Lexer.ts","../src/Renderer.ts","../src/TextRenderer.ts","../src/Parser.ts","../src/Hooks.ts","../src/Instance.ts","../src/marked.ts"],"sourcesContent":["/**\n * Gets the original marked default options.\n */\nexport function _getDefaults() {\n return {\n async: false,\n breaks: false,\n extensions: null,\n gfm: true,\n hooks: null,\n pedantic: false,\n renderer: null,\n silent: false,\n tokenizer: null,\n walkTokens: null,\n };\n}\nexport let _defaults = _getDefaults();\nexport function changeDefaults(newDefaults) {\n _defaults = newDefaults;\n}\n","/**\n * Helpers\n */\nconst escapeTest = /[&<>\"']/;\nconst escapeReplace = new RegExp(escapeTest.source, 'g');\nconst escapeTestNoEncode = /[<>\"']|&(?!(#\\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\\w+);)/;\nconst escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');\nconst escapeReplacements = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n};\nconst getEscapeReplacement = (ch) => escapeReplacements[ch];\nexport function escape(html, encode) {\n if (encode) {\n if (escapeTest.test(html)) {\n return html.replace(escapeReplace, getEscapeReplacement);\n }\n }\n else {\n if (escapeTestNoEncode.test(html)) {\n return html.replace(escapeReplaceNoEncode, getEscapeReplacement);\n }\n }\n return html;\n}\nconst unescapeTest = /&(#(?:\\d+)|(?:#x[0-9A-Fa-f]+)|(?:\\w+));?/ig;\nexport function unescape(html) {\n // explicitly match decimal, hex, and named HTML entities\n return html.replace(unescapeTest, (_, n) => {\n n = n.toLowerCase();\n if (n === 'colon')\n return ':';\n if (n.charAt(0) === '#') {\n return n.charAt(1) === 'x'\n ? String.fromCharCode(parseInt(n.substring(2), 16))\n : String.fromCharCode(+n.substring(1));\n }\n return '';\n });\n}\nconst caret = /(^|[^\\[])\\^/g;\nexport function edit(regex, opt) {\n let source = typeof regex === 'string' ? regex : regex.source;\n opt = opt || '';\n const obj = {\n replace: (name, val) => {\n let valSource = typeof val === 'string' ? val : val.source;\n valSource = valSource.replace(caret, '$1');\n source = source.replace(name, valSource);\n return obj;\n },\n getRegex: () => {\n return new RegExp(source, opt);\n },\n };\n return obj;\n}\nexport function cleanUrl(href) {\n try {\n href = encodeURI(href).replace(/%25/g, '%');\n }\n catch {\n return null;\n }\n return href;\n}\nexport const noopTest = { exec: () => null };\nexport function splitCells(tableRow, count) {\n // ensure that every cell-delimiting pipe has a space\n // before it to distinguish it from an escaped pipe\n const row = tableRow.replace(/\\|/g, (match, offset, str) => {\n let escaped = false;\n let curr = offset;\n while (--curr >= 0 && str[curr] === '\\\\')\n escaped = !escaped;\n if (escaped) {\n // odd number of slashes means | is escaped\n // so we leave it alone\n return '|';\n }\n else {\n // add space before unescaped |\n return ' |';\n }\n }), cells = row.split(/ \\|/);\n let i = 0;\n // First/last cell in a row cannot be empty if it has no leading/trailing pipe\n if (!cells[0].trim()) {\n cells.shift();\n }\n if (cells.length > 0 && !cells[cells.length - 1].trim()) {\n cells.pop();\n }\n if (count) {\n if (cells.length > count) {\n cells.splice(count);\n }\n else {\n while (cells.length < count)\n cells.push('');\n }\n }\n for (; i < cells.length; i++) {\n // leading or trailing whitespace is ignored per the gfm spec\n cells[i] = cells[i].trim().replace(/\\\\\\|/g, '|');\n }\n return cells;\n}\n/**\n * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').\n * /c*$/ is vulnerable to REDOS.\n *\n * @param str\n * @param c\n * @param invert Remove suffix of non-c chars instead. Default falsey.\n */\nexport function rtrim(str, c, invert) {\n const l = str.length;\n if (l === 0) {\n return '';\n }\n // Length of suffix matching the invert condition.\n let suffLen = 0;\n // Step left until we fail to match the invert condition.\n while (suffLen < l) {\n const currChar = str.charAt(l - suffLen - 1);\n if (currChar === c && !invert) {\n suffLen++;\n }\n else if (currChar !== c && invert) {\n suffLen++;\n }\n else {\n break;\n }\n }\n return str.slice(0, l - suffLen);\n}\nexport function findClosingBracket(str, b) {\n if (str.indexOf(b[1]) === -1) {\n return -1;\n }\n let level = 0;\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '\\\\') {\n i++;\n }\n else if (str[i] === b[0]) {\n level++;\n }\n else if (str[i] === b[1]) {\n level--;\n if (level < 0) {\n return i;\n }\n }\n }\n return -1;\n}\n","import { _defaults } from './defaults.ts';\nimport { rtrim, splitCells, escape, findClosingBracket, } from './helpers.ts';\nfunction outputLink(cap, link, raw, lexer) {\n const href = link.href;\n const title = link.title ? escape(link.title) : null;\n const text = cap[1].replace(/\\\\([\\[\\]])/g, '$1');\n if (cap[0].charAt(0) !== '!') {\n lexer.state.inLink = true;\n const token = {\n type: 'link',\n raw,\n href,\n title,\n text,\n tokens: lexer.inlineTokens(text),\n };\n lexer.state.inLink = false;\n return token;\n }\n return {\n type: 'image',\n raw,\n href,\n title,\n text: escape(text),\n };\n}\nfunction indentCodeCompensation(raw, text) {\n const matchIndentToCode = raw.match(/^(\\s+)(?:```)/);\n if (matchIndentToCode === null) {\n return text;\n }\n const indentToCode = matchIndentToCode[1];\n return text\n .split('\\n')\n .map(node => {\n const matchIndentInNode = node.match(/^\\s+/);\n if (matchIndentInNode === null) {\n return node;\n }\n const [indentInNode] = matchIndentInNode;\n if (indentInNode.length >= indentToCode.length) {\n return node.slice(indentToCode.length);\n }\n return node;\n })\n .join('\\n');\n}\n/**\n * Tokenizer\n */\nexport class _Tokenizer {\n options;\n rules; // set by the lexer\n lexer; // set by the lexer\n constructor(options) {\n this.options = options || _defaults;\n }\n space(src) {\n const cap = this.rules.block.newline.exec(src);\n if (cap && cap[0].length > 0) {\n return {\n type: 'space',\n raw: cap[0],\n };\n }\n }\n code(src) {\n const cap = this.rules.block.code.exec(src);\n if (cap) {\n const text = cap[0].replace(/^(?: {1,4}| {0,3}\\t)/gm, '');\n return {\n type: 'code',\n raw: cap[0],\n codeBlockStyle: 'indented',\n text: !this.options.pedantic\n ? rtrim(text, '\\n')\n : text,\n };\n }\n }\n fences(src) {\n const cap = this.rules.block.fences.exec(src);\n if (cap) {\n const raw = cap[0];\n const text = indentCodeCompensation(raw, cap[3] || '');\n return {\n type: 'code',\n raw,\n lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],\n text,\n };\n }\n }\n heading(src) {\n const cap = this.rules.block.heading.exec(src);\n if (cap) {\n let text = cap[2].trim();\n // remove trailing #s\n if (/#$/.test(text)) {\n const trimmed = rtrim(text, '#');\n if (this.options.pedantic) {\n text = trimmed.trim();\n }\n else if (!trimmed || / $/.test(trimmed)) {\n // CommonMark requires space before trailing #s\n text = trimmed.trim();\n }\n }\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[1].length,\n text,\n tokens: this.lexer.inline(text),\n };\n }\n }\n hr(src) {\n const cap = this.rules.block.hr.exec(src);\n if (cap) {\n return {\n type: 'hr',\n raw: rtrim(cap[0], '\\n'),\n };\n }\n }\n blockquote(src) {\n const cap = this.rules.block.blockquote.exec(src);\n if (cap) {\n let lines = rtrim(cap[0], '\\n').split('\\n');\n let raw = '';\n let text = '';\n const tokens = [];\n while (lines.length > 0) {\n let inBlockquote = false;\n const currentLines = [];\n let i;\n for (i = 0; i < lines.length; i++) {\n // get lines up to a continuation\n if (/^ {0,3}>/.test(lines[i])) {\n currentLines.push(lines[i]);\n inBlockquote = true;\n }\n else if (!inBlockquote) {\n currentLines.push(lines[i]);\n }\n else {\n break;\n }\n }\n lines = lines.slice(i);\n const currentRaw = currentLines.join('\\n');\n const currentText = currentRaw\n // precede setext continuation with 4 spaces so it isn't a setext\n .replace(/\\n {0,3}((?:=+|-+) *)(?=\\n|$)/g, '\\n $1')\n .replace(/^ {0,3}>[ \\t]?/gm, '');\n raw = raw ? `${raw}\\n${currentRaw}` : currentRaw;\n text = text ? `${text}\\n${currentText}` : currentText;\n // parse blockquote lines as top level tokens\n // merge paragraphs if this is a continuation\n const top = this.lexer.state.top;\n this.lexer.state.top = true;\n this.lexer.blockTokens(currentText, tokens, true);\n this.lexer.state.top = top;\n // if there is no continuation then we are done\n if (lines.length === 0) {\n break;\n }\n const lastToken = tokens[tokens.length - 1];\n if (lastToken?.type === 'code') {\n // blockquote continuation cannot be preceded by a code block\n break;\n }\n else if (lastToken?.type === 'blockquote') {\n // include continuation in nested blockquote\n const oldToken = lastToken;\n const newText = oldToken.raw + '\\n' + lines.join('\\n');\n const newToken = this.blockquote(newText);\n tokens[tokens.length - 1] = newToken;\n raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw;\n text = text.substring(0, text.length - oldToken.text.length) + newToken.text;\n break;\n }\n else if (lastToken?.type === 'list') {\n // include continuation in nested list\n const oldToken = lastToken;\n const newText = oldToken.raw + '\\n' + lines.join('\\n');\n const newToken = this.list(newText);\n tokens[tokens.length - 1] = newToken;\n raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw;\n text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw;\n lines = newText.substring(tokens[tokens.length - 1].raw.length).split('\\n');\n continue;\n }\n }\n return {\n type: 'blockquote',\n raw,\n tokens,\n text,\n };\n }\n }\n list(src) {\n let cap = this.rules.block.list.exec(src);\n if (cap) {\n let bull = cap[1].trim();\n const isordered = bull.length > 1;\n const list = {\n type: 'list',\n raw: '',\n ordered: isordered,\n start: isordered ? +bull.slice(0, -1) : '',\n loose: false,\n items: [],\n };\n bull = isordered ? `\\\\d{1,9}\\\\${bull.slice(-1)}` : `\\\\${bull}`;\n if (this.options.pedantic) {\n bull = isordered ? bull : '[*+-]';\n }\n // Get next list item\n const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\\t ][^\\\\n]*)?(?:\\\\n|$))`);\n let endsWithBlankLine = false;\n // Check if current bullet point can start a new List Item\n while (src) {\n let endEarly = false;\n let raw = '';\n let itemContents = '';\n if (!(cap = itemRegex.exec(src))) {\n break;\n }\n if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)\n break;\n }\n raw = cap[0];\n src = src.substring(raw.length);\n let line = cap[2].split('\\n', 1)[0].replace(/^\\t+/, (t) => ' '.repeat(3 * t.length));\n let nextLine = src.split('\\n', 1)[0];\n let blankLine = !line.trim();\n let indent = 0;\n if (this.options.pedantic) {\n indent = 2;\n itemContents = line.trimStart();\n }\n else if (blankLine) {\n indent = cap[1].length + 1;\n }\n else {\n indent = cap[2].search(/[^ ]/); // Find first non-space char\n indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent\n itemContents = line.slice(indent);\n indent += cap[1].length;\n }\n if (blankLine && /^[ \\t]*$/.test(nextLine)) { // Items begin with at most one blank line\n raw += nextLine + '\\n';\n src = src.substring(nextLine.length + 1);\n endEarly = true;\n }\n if (!endEarly) {\n const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\\\d{1,9}[.)])((?:[ \\t][^\\\\n]*)?(?:\\\\n|$))`);\n const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)`);\n const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\\`\\`\\`|~~~)`);\n const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);\n const htmlBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}<[a-z].*>`, 'i');\n // Check if following lines should be included in List Item\n while (src) {\n const rawLine = src.split('\\n', 1)[0];\n let nextLineWithoutTabs;\n nextLine = rawLine;\n // Re-align to follow commonmark nesting rules\n if (this.options.pedantic) {\n nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');\n nextLineWithoutTabs = nextLine;\n }\n else {\n nextLineWithoutTabs = nextLine.replace(/\\t/g, ' ');\n }\n // End list item if found code fences\n if (fencesBeginRegex.test(nextLine)) {\n break;\n }\n // End list item if found start of new heading\n if (headingBeginRegex.test(nextLine)) {\n break;\n }\n // End list item if found start of html block\n if (htmlBeginRegex.test(nextLine)) {\n break;\n }\n // End list item if found start of new bullet\n if (nextBulletRegex.test(nextLine)) {\n break;\n }\n // Horizontal rule found\n if (hrRegex.test(nextLine)) {\n break;\n }\n if (nextLineWithoutTabs.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible\n itemContents += '\\n' + nextLineWithoutTabs.slice(indent);\n }\n else {\n // not enough indentation\n if (blankLine) {\n break;\n }\n // paragraph continuation unless last line was a different block level element\n if (line.replace(/\\t/g, ' ').search(/[^ ]/) >= 4) { // indented code block\n break;\n }\n if (fencesBeginRegex.test(line)) {\n break;\n }\n if (headingBeginRegex.test(line)) {\n break;\n }\n if (hrRegex.test(line)) {\n break;\n }\n itemContents += '\\n' + nextLine;\n }\n if (!blankLine && !nextLine.trim()) { // Check if current line is blank\n blankLine = true;\n }\n raw += rawLine + '\\n';\n src = src.substring(rawLine.length + 1);\n line = nextLineWithoutTabs.slice(indent);\n }\n }\n if (!list.loose) {\n // If the previous item ended with a blank line, the list is loose\n if (endsWithBlankLine) {\n list.loose = true;\n }\n else if (/\\n[ \\t]*\\n[ \\t]*$/.test(raw)) {\n endsWithBlankLine = true;\n }\n }\n let istask = null;\n let ischecked;\n // Check for task list items\n if (this.options.gfm) {\n istask = /^\\[[ xX]\\] /.exec(itemContents);\n if (istask) {\n ischecked = istask[0] !== '[ ] ';\n itemContents = itemContents.replace(/^\\[[ xX]\\] +/, '');\n }\n }\n list.items.push({\n type: 'list_item',\n raw,\n task: !!istask,\n checked: ischecked,\n loose: false,\n text: itemContents,\n tokens: [],\n });\n list.raw += raw;\n }\n // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic\n list.items[list.items.length - 1].raw = list.items[list.items.length - 1].raw.trimEnd();\n list.items[list.items.length - 1].text = list.items[list.items.length - 1].text.trimEnd();\n list.raw = list.raw.trimEnd();\n // Item child tokens handled here at end because we needed to have the final item to trim it first\n for (let i = 0; i < list.items.length; i++) {\n this.lexer.state.top = false;\n list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);\n if (!list.loose) {\n // Check if list should be loose\n const spacers = list.items[i].tokens.filter(t => t.type === 'space');\n const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\\n.*\\n/.test(t.raw));\n list.loose = hasMultipleLineBreaks;\n }\n }\n // Set all items to loose if list is loose\n if (list.loose) {\n for (let i = 0; i < list.items.length; i++) {\n list.items[i].loose = true;\n }\n }\n return list;\n }\n }\n html(src) {\n const cap = this.rules.block.html.exec(src);\n if (cap) {\n const token = {\n type: 'html',\n block: true,\n raw: cap[0],\n pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',\n text: cap[0],\n };\n return token;\n }\n }\n def(src) {\n const cap = this.rules.block.def.exec(src);\n if (cap) {\n const tag = cap[1].toLowerCase().replace(/\\s+/g, ' ');\n const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';\n const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];\n return {\n type: 'def',\n tag,\n raw: cap[0],\n href,\n title,\n };\n }\n }\n table(src) {\n const cap = this.rules.block.table.exec(src);\n if (!cap) {\n return;\n }\n if (!/[:|]/.test(cap[2])) {\n // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading\n return;\n }\n const headers = splitCells(cap[1]);\n const aligns = cap[2].replace(/^\\||\\| *$/g, '').split('|');\n const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\\n[ \\t]*$/, '').split('\\n') : [];\n const item = {\n type: 'table',\n raw: cap[0],\n header: [],\n align: [],\n rows: [],\n };\n if (headers.length !== aligns.length) {\n // header and align columns must be equal, rows can be different.\n return;\n }\n for (const align of aligns) {\n if (/^ *-+: *$/.test(align)) {\n item.align.push('right');\n }\n else if (/^ *:-+: *$/.test(align)) {\n item.align.push('center');\n }\n else if (/^ *:-+ *$/.test(align)) {\n item.align.push('left');\n }\n else {\n item.align.push(null);\n }\n }\n for (let i = 0; i < headers.length; i++) {\n item.header.push({\n text: headers[i],\n tokens: this.lexer.inline(headers[i]),\n header: true,\n align: item.align[i],\n });\n }\n for (const row of rows) {\n item.rows.push(splitCells(row, item.header.length).map((cell, i) => {\n return {\n text: cell,\n tokens: this.lexer.inline(cell),\n header: false,\n align: item.align[i],\n };\n }));\n }\n return item;\n }\n lheading(src) {\n const cap = this.rules.block.lheading.exec(src);\n if (cap) {\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[2].charAt(0) === '=' ? 1 : 2,\n text: cap[1],\n tokens: this.lexer.inline(cap[1]),\n };\n }\n }\n paragraph(src) {\n const cap = this.rules.block.paragraph.exec(src);\n if (cap) {\n const text = cap[1].charAt(cap[1].length - 1) === '\\n'\n ? cap[1].slice(0, -1)\n : cap[1];\n return {\n type: 'paragraph',\n raw: cap[0],\n text,\n tokens: this.lexer.inline(text),\n };\n }\n }\n text(src) {\n const cap = this.rules.block.text.exec(src);\n if (cap) {\n return {\n type: 'text',\n raw: cap[0],\n text: cap[0],\n tokens: this.lexer.inline(cap[0]),\n };\n }\n }\n escape(src) {\n const cap = this.rules.inline.escape.exec(src);\n if (cap) {\n return {\n type: 'escape',\n raw: cap[0],\n text: escape(cap[1]),\n };\n }\n }\n tag(src) {\n const cap = this.rules.inline.tag.exec(src);\n if (cap) {\n if (!this.lexer.state.inLink && /^
    /i.test(cap[0])) {\n this.lexer.state.inLink = false;\n }\n if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n this.lexer.state.inRawBlock = true;\n }\n else if (this.lexer.state.inRawBlock && /^<\\/(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n this.lexer.state.inRawBlock = false;\n }\n return {\n type: 'html',\n raw: cap[0],\n inLink: this.lexer.state.inLink,\n inRawBlock: this.lexer.state.inRawBlock,\n block: false,\n text: cap[0],\n };\n }\n }\n link(src) {\n const cap = this.rules.inline.link.exec(src);\n if (cap) {\n const trimmedUrl = cap[2].trim();\n if (!this.options.pedantic && /^$/.test(trimmedUrl))) {\n return;\n }\n // ending angle bracket cannot be escaped\n const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\\\');\n if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {\n return;\n }\n }\n else {\n // find closing parenthesis\n const lastParenIndex = findClosingBracket(cap[2], '()');\n if (lastParenIndex > -1) {\n const start = cap[0].indexOf('!') === 0 ? 5 : 4;\n const linkLen = start + cap[1].length + lastParenIndex;\n cap[2] = cap[2].substring(0, lastParenIndex);\n cap[0] = cap[0].substring(0, linkLen).trim();\n cap[3] = '';\n }\n }\n let href = cap[2];\n let title = '';\n if (this.options.pedantic) {\n // split pedantic href and title\n const link = /^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/.exec(href);\n if (link) {\n href = link[1];\n title = link[3];\n }\n }\n else {\n title = cap[3] ? cap[3].slice(1, -1) : '';\n }\n href = href.trim();\n if (/^$/.test(trimmedUrl))) {\n // pedantic allows starting angle bracket without ending angle bracket\n href = href.slice(1);\n }\n else {\n href = href.slice(1, -1);\n }\n }\n return outputLink(cap, {\n href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,\n title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title,\n }, cap[0], this.lexer);\n }\n }\n reflink(src, links) {\n let cap;\n if ((cap = this.rules.inline.reflink.exec(src))\n || (cap = this.rules.inline.nolink.exec(src))) {\n const linkString = (cap[2] || cap[1]).replace(/\\s+/g, ' ');\n const link = links[linkString.toLowerCase()];\n if (!link) {\n const text = cap[0].charAt(0);\n return {\n type: 'text',\n raw: text,\n text,\n };\n }\n return outputLink(cap, link, cap[0], this.lexer);\n }\n }\n emStrong(src, maskedSrc, prevChar = '') {\n let match = this.rules.inline.emStrongLDelim.exec(src);\n if (!match)\n return;\n // _ can't be between two alphanumerics. \\p{L}\\p{N} includes non-english alphabet/numbers as well\n if (match[3] && prevChar.match(/[\\p{L}\\p{N}]/u))\n return;\n const nextChar = match[1] || match[2] || '';\n if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {\n // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)\n const lLength = [...match[0]].length - 1;\n let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;\n const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;\n endReg.lastIndex = 0;\n // Clip maskedSrc to same section of string as src (move to lexer?)\n maskedSrc = maskedSrc.slice(-1 * src.length + lLength);\n while ((match = endReg.exec(maskedSrc)) != null) {\n rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];\n if (!rDelim)\n continue; // skip single * in __abc*abc__\n rLength = [...rDelim].length;\n if (match[3] || match[4]) { // found another Left Delim\n delimTotal += rLength;\n continue;\n }\n else if (match[5] || match[6]) { // either Left or Right Delim\n if (lLength % 3 && !((lLength + rLength) % 3)) {\n midDelimTotal += rLength;\n continue; // CommonMark Emphasis Rules 9-10\n }\n }\n delimTotal -= rLength;\n if (delimTotal > 0)\n continue; // Haven't found enough closing delimiters\n // Remove extra characters. *a*** -> *a*\n rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);\n // char length can be >1 for unicode characters;\n const lastCharLength = [...match[0]][0].length;\n const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);\n // Create `em` if smallest delimiter has odd char count. *a***\n if (Math.min(lLength, rLength) % 2) {\n const text = raw.slice(1, -1);\n return {\n type: 'em',\n raw,\n text,\n tokens: this.lexer.inlineTokens(text),\n };\n }\n // Create 'strong' if smallest delimiter has even char count. **a***\n const text = raw.slice(2, -2);\n return {\n type: 'strong',\n raw,\n text,\n tokens: this.lexer.inlineTokens(text),\n };\n }\n }\n }\n codespan(src) {\n const cap = this.rules.inline.code.exec(src);\n if (cap) {\n let text = cap[2].replace(/\\n/g, ' ');\n const hasNonSpaceChars = /[^ ]/.test(text);\n const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);\n if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {\n text = text.substring(1, text.length - 1);\n }\n text = escape(text, true);\n return {\n type: 'codespan',\n raw: cap[0],\n text,\n };\n }\n }\n br(src) {\n const cap = this.rules.inline.br.exec(src);\n if (cap) {\n return {\n type: 'br',\n raw: cap[0],\n };\n }\n }\n del(src) {\n const cap = this.rules.inline.del.exec(src);\n if (cap) {\n return {\n type: 'del',\n raw: cap[0],\n text: cap[2],\n tokens: this.lexer.inlineTokens(cap[2]),\n };\n }\n }\n autolink(src) {\n const cap = this.rules.inline.autolink.exec(src);\n if (cap) {\n let text, href;\n if (cap[2] === '@') {\n text = escape(cap[1]);\n href = 'mailto:' + text;\n }\n else {\n text = escape(cap[1]);\n href = text;\n }\n return {\n type: 'link',\n raw: cap[0],\n text,\n href,\n tokens: [\n {\n type: 'text',\n raw: text,\n text,\n },\n ],\n };\n }\n }\n url(src) {\n let cap;\n if (cap = this.rules.inline.url.exec(src)) {\n let text, href;\n if (cap[2] === '@') {\n text = escape(cap[0]);\n href = 'mailto:' + text;\n }\n else {\n // do extended autolink path validation\n let prevCapZero;\n do {\n prevCapZero = cap[0];\n cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';\n } while (prevCapZero !== cap[0]);\n text = escape(cap[0]);\n if (cap[1] === 'www.') {\n href = 'http://' + cap[0];\n }\n else {\n href = cap[0];\n }\n }\n return {\n type: 'link',\n raw: cap[0],\n text,\n href,\n tokens: [\n {\n type: 'text',\n raw: text,\n text,\n },\n ],\n };\n }\n }\n inlineText(src) {\n const cap = this.rules.inline.text.exec(src);\n if (cap) {\n let text;\n if (this.lexer.state.inRawBlock) {\n text = cap[0];\n }\n else {\n text = escape(cap[0]);\n }\n return {\n type: 'text',\n raw: cap[0],\n text,\n };\n }\n }\n}\n","import { edit, noopTest, } from './helpers.ts';\n/**\n * Block-Level Grammar\n */\nconst newline = /^(?:[ \\t]*(?:\\n|$))+/;\nconst blockCode = /^((?: {4}| {0,3}\\t)[^\\n]+(?:\\n(?:[ \\t]*(?:\\n|$))*)?)+/;\nconst fences = /^ {0,3}(`{3,}(?=[^`\\n]*(?:\\n|$))|~{3,})([^\\n]*)(?:\\n|$)(?:|([\\s\\S]*?)(?:\\n|$))(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/;\nconst hr = /^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/;\nconst heading = /^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/;\nconst bullet = /(?:[*+-]|\\d{1,9}[.)])/;\nconst lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\\n(?!\\s*?\\n|bull |blockCode|fences|blockquote|heading|html))+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/)\n .replace(/bull/g, bullet) // lists can interrupt\n .replace(/blockCode/g, /(?: {4}| {0,3}\\t)/) // indented code blocks can interrupt\n .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt\n .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt\n .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt\n .replace(/html/g, / {0,3}<[^\\n>]+>\\n/) // block html can interrupt\n .getRegex();\nconst _paragraph = /^([^\\n]+(?:\\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\\n)[^\\n]+)*)/;\nconst blockText = /^[^\\n]+/;\nconst _blockLabel = /(?!\\s*\\])(?:\\\\.|[^\\[\\]\\\\])+/;\nconst def = edit(/^ {0,3}\\[(label)\\]: *(?:\\n[ \\t]*)?([^<\\s][^\\s]*|<.*?>)(?:(?: +(?:\\n[ \\t]*)?| *\\n[ \\t]*)(title))? *(?:\\n+|$)/)\n .replace('label', _blockLabel)\n .replace('title', /(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/)\n .getRegex();\nconst list = edit(/^( {0,3}bull)([ \\t][^\\n]+?)?(?:\\n|$)/)\n .replace(/bull/g, bullet)\n .getRegex();\nconst _tag = 'address|article|aside|base|basefont|blockquote|body|caption'\n + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'\n + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'\n + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'\n + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title'\n + '|tr|track|ul';\nconst _comment = /|$))/;\nconst html = edit('^ {0,3}(?:' // optional indentation\n + '<(script|pre|style|textarea)[\\\\s>][\\\\s\\\\S]*?(?:[^\\\\n]*\\\\n+|$)' // (1)\n + '|comment[^\\\\n]*(\\\\n+|$)' // (2)\n + '|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>\\\\n*|$)' // (3)\n + '|\\\\n*|$)' // (4)\n + '|\\\\n*|$)' // (5)\n + '|)[\\\\s\\\\S]*?(?:(?:\\\\n[ \\t]*)+\\\\n|$)' // (6)\n + '|<(?!script|pre|style|textarea)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n[ \\t]*)+\\\\n|$)' // (7) open tag\n + '|(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n[ \\t]*)+\\\\n|$)' // (7) closing tag\n + ')', 'i')\n .replace('comment', _comment)\n .replace('tag', _tag)\n .replace('attribute', / +[a-zA-Z:_][\\w.:-]*(?: *= *\"[^\"\\n]*\"| *= *'[^'\\n]*'| *= *[^\\s\"'=<>`]+)?/)\n .getRegex();\nconst paragraph = edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs\n .replace('|table', '')\n .replace('blockquote', ' {0,3}>')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // pars can be interrupted by type (6) html blocks\n .getRegex();\nconst blockquote = edit(/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/)\n .replace('paragraph', paragraph)\n .getRegex();\n/**\n * Normal Block Grammar\n */\nconst blockNormal = {\n blockquote,\n code: blockCode,\n def,\n fences,\n heading,\n hr,\n html,\n lheading,\n list,\n newline,\n paragraph,\n table: noopTest,\n text: blockText,\n};\n/**\n * GFM Block Grammar\n */\nconst gfmTable = edit('^ *([^\\\\n ].*)\\\\n' // Header\n + ' {0,3}((?:\\\\| *)?:?-+:? *(?:\\\\| *:?-+:? *)*(?:\\\\| *)?)' // Align\n + '(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)') // Cells\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('blockquote', ' {0,3}>')\n .replace('code', '(?: {4}| {0,3}\\t)[^\\\\n]')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // tables can be interrupted by type (6) html blocks\n .getRegex();\nconst blockGfm = {\n ...blockNormal,\n table: gfmTable,\n paragraph: edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs\n .replace('table', gfmTable) // interrupt paragraphs with table\n .replace('blockquote', ' {0,3}>')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // pars can be interrupted by type (6) html blocks\n .getRegex(),\n};\n/**\n * Pedantic grammar (original John Gruber's loose markdown specification)\n */\nconst blockPedantic = {\n ...blockNormal,\n html: edit('^ *(?:comment *(?:\\\\n|\\\\s*$)'\n + '|<(tag)[\\\\s\\\\S]+? *(?:\\\\n{2,}|\\\\s*$)' // closed tag\n + '|\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))')\n .replace('comment', _comment)\n .replace(/tag/g, '(?!(?:'\n + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'\n + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'\n + '\\\\b)\\\\w+(?!:|[^\\\\w\\\\s@]*@)\\\\b')\n .getRegex(),\n def: /^ *\\[([^\\]]+)\\]: *]+)>?(?: +([\"(][^\\n]+[\")]))? *(?:\\n+|$)/,\n heading: /^(#{1,6})(.*)(?:\\n+|$)/,\n fences: noopTest, // fences not supported\n lheading: /^(.+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,\n paragraph: edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' *#{1,6} *[^\\n]')\n .replace('lheading', lheading)\n .replace('|table', '')\n .replace('blockquote', ' {0,3}>')\n .replace('|fences', '')\n .replace('|list', '')\n .replace('|html', '')\n .replace('|tag', '')\n .getRegex(),\n};\n/**\n * Inline-Level Grammar\n */\nconst escape = /^\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/;\nconst inlineCode = /^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/;\nconst br = /^( {2,}|\\\\)\\n(?!\\s*$)/;\nconst inlineText = /^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\\nconst blockSkip = /\\[[^[\\]]*?\\]\\((?:\\\\.|[^\\\\\\(\\)]|\\((?:\\\\.|[^\\\\\\(\\)])*\\))*\\)|`[^`]*?`|<[^<>]*?>/g;\nconst emStrongLDelim = edit(/^(?:\\*+(?:((?!\\*)[punct])|[^\\s*]))|^_+(?:((?!_)[punct])|([^\\s_]))/, 'u')\n .replace(/punct/g, _punctuation)\n .getRegex();\nconst emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\\\*[^_*]*?(?=__)' // Skip orphan inside strong\n + '|[^*]+(?=[^*])' // Consume to delim\n + '|(?!\\\\*)[punct](\\\\*+)(?=[\\\\s]|$)' // (1) #*** can only be a Right Delimiter\n + '|[^punct\\\\s](\\\\*+)(?!\\\\*)(?=[punct\\\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter\n + '|(?!\\\\*)[punct\\\\s](\\\\*+)(?=[^punct\\\\s])' // (3) #***a, ***a can only be Left Delimiter\n + '|[\\\\s](\\\\*+)(?!\\\\*)(?=[punct])' // (4) ***# can only be Left Delimiter\n + '|(?!\\\\*)[punct](\\\\*+)(?!\\\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter\n + '|[^punct\\\\s](\\\\*+)(?=[^punct\\\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter\n .replace(/punct/g, _punctuation)\n .getRegex();\n// (6) Not allowed for _\nconst emStrongRDelimUnd = edit('^[^_*]*?\\\\*\\\\*[^_*]*?_[^_*]*?(?=\\\\*\\\\*)' // Skip orphan inside strong\n + '|[^_]+(?=[^_])' // Consume to delim\n + '|(?!_)[punct](_+)(?=[\\\\s]|$)' // (1) #___ can only be a Right Delimiter\n + '|[^punct\\\\s](_+)(?!_)(?=[punct\\\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter\n + '|(?!_)[punct\\\\s](_+)(?=[^punct\\\\s])' // (3) #___a, ___a can only be Left Delimiter\n + '|[\\\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter\n + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter\n .replace(/punct/g, _punctuation)\n .getRegex();\nconst anyPunctuation = edit(/\\\\([punct])/, 'gu')\n .replace(/punct/g, _punctuation)\n .getRegex();\nconst autolink = edit(/^<(scheme:[^\\s\\x00-\\x1f<>]*|email)>/)\n .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)\n .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/)\n .getRegex();\nconst _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();\nconst tag = edit('^comment'\n + '|^' // self-closing tag\n + '|^<[a-zA-Z][\\\\w-]*(?:attribute)*?\\\\s*/?>' // open tag\n + '|^<\\\\?[\\\\s\\\\S]*?\\\\?>' // processing instruction, e.g. \n + '|^' // declaration, e.g. \n + '|^') // CDATA section\n .replace('comment', _inlineComment)\n .replace('attribute', /\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*\"[^\"]*\"|\\s*=\\s*'[^']*'|\\s*=\\s*[^\\s\"'=<>`]+)?/)\n .getRegex();\nconst _inlineLabel = /(?:\\[(?:\\\\.|[^\\[\\]\\\\])*\\]|\\\\.|`[^`]*`|[^\\[\\]\\\\`])*?/;\nconst link = edit(/^!?\\[(label)\\]\\(\\s*(href)(?:\\s+(title))?\\s*\\)/)\n .replace('label', _inlineLabel)\n .replace('href', /<(?:\\\\.|[^\\n<>\\\\])+>|[^\\s\\x00-\\x1f]*/)\n .replace('title', /\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/)\n .getRegex();\nconst reflink = edit(/^!?\\[(label)\\]\\[(ref)\\]/)\n .replace('label', _inlineLabel)\n .replace('ref', _blockLabel)\n .getRegex();\nconst nolink = edit(/^!?\\[(ref)\\](?:\\[\\])?/)\n .replace('ref', _blockLabel)\n .getRegex();\nconst reflinkSearch = edit('reflink|nolink(?!\\\\()', 'g')\n .replace('reflink', reflink)\n .replace('nolink', nolink)\n .getRegex();\n/**\n * Normal Inline Grammar\n */\nconst inlineNormal = {\n _backpedal: noopTest, // only used for GFM url\n anyPunctuation,\n autolink,\n blockSkip,\n br,\n code: inlineCode,\n del: noopTest,\n emStrongLDelim,\n emStrongRDelimAst,\n emStrongRDelimUnd,\n escape,\n link,\n nolink,\n punctuation,\n reflink,\n reflinkSearch,\n tag,\n text: inlineText,\n url: noopTest,\n};\n/**\n * Pedantic Inline Grammar\n */\nconst inlinePedantic = {\n ...inlineNormal,\n link: edit(/^!?\\[(label)\\]\\((.*?)\\)/)\n .replace('label', _inlineLabel)\n .getRegex(),\n reflink: edit(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/)\n .replace('label', _inlineLabel)\n .getRegex(),\n};\n/**\n * GFM Inline Grammar\n */\nconst inlineGfm = {\n ...inlineNormal,\n escape: edit(escape).replace('])', '~|])').getRegex(),\n url: edit(/^((?:ftp|https?):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/, 'i')\n .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)\n .getRegex(),\n _backpedal: /(?:[^?!.,:;*_'\"~()&]+|\\([^)]*\\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'\"~)]+(?!$))+/,\n del: /^(~~?)(?=[^\\s~])([\\s\\S]*?[^\\s~])\\1(?=[^~]|$)/,\n text: /^([`~]+|[^`~])(?:(?= {2,}\\n)|(?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)|[\\s\\S]*?(?:(?=[\\\\ {\n if (token = extTokenizer.call({ lexer: this }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n return false;\n })) {\n continue;\n }\n // newline\n if (token = this.tokenizer.space(src)) {\n src = src.substring(token.raw.length);\n if (token.raw.length === 1 && tokens.length > 0) {\n // if there's a single \\n as a spacer, it's terminating the last line,\n // so move it there so that we don't get unnecessary paragraph tags\n tokens[tokens.length - 1].raw += '\\n';\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // code\n if (token = this.tokenizer.code(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n // An indented code block cannot interrupt a paragraph.\n if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // fences\n if (token = this.tokenizer.fences(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // heading\n if (token = this.tokenizer.heading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // hr\n if (token = this.tokenizer.hr(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // blockquote\n if (token = this.tokenizer.blockquote(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // list\n if (token = this.tokenizer.list(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // html\n if (token = this.tokenizer.html(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // def\n if (token = this.tokenizer.def(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.raw;\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else if (!this.tokens.links[token.tag]) {\n this.tokens.links[token.tag] = {\n href: token.href,\n title: token.title,\n };\n }\n continue;\n }\n // table (gfm)\n if (token = this.tokenizer.table(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // lheading\n if (token = this.tokenizer.lheading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // top-level paragraph\n // prevent paragraph consuming extensions by clipping 'src' to extension start\n cutSrc = src;\n if (this.options.extensions && this.options.extensions.startBlock) {\n let startIndex = Infinity;\n const tempSrc = src.slice(1);\n let tempStart;\n this.options.extensions.startBlock.forEach((getStartIndex) => {\n tempStart = getStartIndex.call({ lexer: this }, tempSrc);\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n }\n if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {\n lastToken = tokens[tokens.length - 1];\n if (lastParagraphClipped && lastToken?.type === 'paragraph') {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else {\n tokens.push(token);\n }\n lastParagraphClipped = (cutSrc.length !== src.length);\n src = src.substring(token.raw.length);\n continue;\n }\n // text\n if (token = this.tokenizer.text(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && lastToken.type === 'text') {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n if (src) {\n const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n if (this.options.silent) {\n console.error(errMsg);\n break;\n }\n else {\n throw new Error(errMsg);\n }\n }\n }\n this.state.top = true;\n return tokens;\n }\n inline(src, tokens = []) {\n this.inlineQueue.push({ src, tokens });\n return tokens;\n }\n /**\n * Lexing/Compiling\n */\n inlineTokens(src, tokens = []) {\n let token, lastToken, cutSrc;\n // String with links masked to avoid interference with em and strong\n let maskedSrc = src;\n let match;\n let keepPrevChar, prevChar;\n // Mask out reflinks\n if (this.tokens.links) {\n const links = Object.keys(this.tokens.links);\n if (links.length > 0) {\n while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {\n if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {\n maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);\n }\n }\n }\n }\n // Mask out other blocks\n while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);\n }\n // Mask out escaped characters\n while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);\n }\n while (src) {\n if (!keepPrevChar) {\n prevChar = '';\n }\n keepPrevChar = false;\n // extensions\n if (this.options.extensions\n && this.options.extensions.inline\n && this.options.extensions.inline.some((extTokenizer) => {\n if (token = extTokenizer.call({ lexer: this }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n return false;\n })) {\n continue;\n }\n // escape\n if (token = this.tokenizer.escape(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // tag\n if (token = this.tokenizer.tag(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && token.type === 'text' && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // link\n if (token = this.tokenizer.link(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // reflink, nolink\n if (token = this.tokenizer.reflink(src, this.tokens.links)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && token.type === 'text' && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // em & strong\n if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // code\n if (token = this.tokenizer.codespan(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // br\n if (token = this.tokenizer.br(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // del (gfm)\n if (token = this.tokenizer.del(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // autolink\n if (token = this.tokenizer.autolink(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // url (gfm)\n if (!this.state.inLink && (token = this.tokenizer.url(src))) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // text\n // prevent inlineText consuming extensions by clipping 'src' to extension start\n cutSrc = src;\n if (this.options.extensions && this.options.extensions.startInline) {\n let startIndex = Infinity;\n const tempSrc = src.slice(1);\n let tempStart;\n this.options.extensions.startInline.forEach((getStartIndex) => {\n tempStart = getStartIndex.call({ lexer: this }, tempSrc);\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n }\n if (token = this.tokenizer.inlineText(cutSrc)) {\n src = src.substring(token.raw.length);\n if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started\n prevChar = token.raw.slice(-1);\n }\n keepPrevChar = true;\n lastToken = tokens[tokens.length - 1];\n if (lastToken && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n if (src) {\n const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n if (this.options.silent) {\n console.error(errMsg);\n break;\n }\n else {\n throw new Error(errMsg);\n }\n }\n }\n return tokens;\n }\n}\n","import { _defaults } from './defaults.ts';\nimport { cleanUrl, escape, } from './helpers.ts';\n/**\n * Renderer\n */\nexport class _Renderer {\n options;\n parser; // set by the parser\n constructor(options) {\n this.options = options || _defaults;\n }\n space(token) {\n return '';\n }\n code({ text, lang, escaped }) {\n const langString = (lang || '').match(/^\\S*/)?.[0];\n const code = text.replace(/\\n$/, '') + '\\n';\n if (!langString) {\n return '
    '\n                + (escaped ? code : escape(code, true))\n                + '
    \\n';\n }\n return '
    '\n            + (escaped ? code : escape(code, true))\n            + '
    \\n';\n }\n blockquote({ tokens }) {\n const body = this.parser.parse(tokens);\n return `
    \\n${body}
    \\n`;\n }\n html({ text }) {\n return text;\n }\n heading({ tokens, depth }) {\n return `${this.parser.parseInline(tokens)}\\n`;\n }\n hr(token) {\n return '
    \\n';\n }\n list(token) {\n const ordered = token.ordered;\n const start = token.start;\n let body = '';\n for (let j = 0; j < token.items.length; j++) {\n const item = token.items[j];\n body += this.listitem(item);\n }\n const type = ordered ? 'ol' : 'ul';\n const startAttr = (ordered && start !== 1) ? (' start=\"' + start + '\"') : '';\n return '<' + type + startAttr + '>\\n' + body + '\\n';\n }\n listitem(item) {\n let itemBody = '';\n if (item.task) {\n const checkbox = this.checkbox({ checked: !!item.checked });\n if (item.loose) {\n if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {\n item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;\n if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {\n item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;\n }\n }\n else {\n item.tokens.unshift({\n type: 'text',\n raw: checkbox + ' ',\n text: checkbox + ' ',\n });\n }\n }\n else {\n itemBody += checkbox + ' ';\n }\n }\n itemBody += this.parser.parse(item.tokens, !!item.loose);\n return `
  • ${itemBody}
  • \\n`;\n }\n checkbox({ checked }) {\n return '';\n }\n paragraph({ tokens }) {\n return `

    ${this.parser.parseInline(tokens)}

    \\n`;\n }\n table(token) {\n let header = '';\n // header\n let cell = '';\n for (let j = 0; j < token.header.length; j++) {\n cell += this.tablecell(token.header[j]);\n }\n header += this.tablerow({ text: cell });\n let body = '';\n for (let j = 0; j < token.rows.length; j++) {\n const row = token.rows[j];\n cell = '';\n for (let k = 0; k < row.length; k++) {\n cell += this.tablecell(row[k]);\n }\n body += this.tablerow({ text: cell });\n }\n if (body)\n body = `${body}`;\n return '\\n'\n + '\\n'\n + header\n + '\\n'\n + body\n + '
    \\n';\n }\n tablerow({ text }) {\n return `\\n${text}\\n`;\n }\n tablecell(token) {\n const content = this.parser.parseInline(token.tokens);\n const type = token.header ? 'th' : 'td';\n const tag = token.align\n ? `<${type} align=\"${token.align}\">`\n : `<${type}>`;\n return tag + content + `\\n`;\n }\n /**\n * span level renderer\n */\n strong({ tokens }) {\n return `${this.parser.parseInline(tokens)}`;\n }\n em({ tokens }) {\n return `${this.parser.parseInline(tokens)}`;\n }\n codespan({ text }) {\n return `${text}`;\n }\n br(token) {\n return '
    ';\n }\n del({ tokens }) {\n return `${this.parser.parseInline(tokens)}`;\n }\n link({ href, title, tokens }) {\n const text = this.parser.parseInline(tokens);\n const cleanHref = cleanUrl(href);\n if (cleanHref === null) {\n return text;\n }\n href = cleanHref;\n let out = '
    ';\n return out;\n }\n image({ href, title, text }) {\n const cleanHref = cleanUrl(href);\n if (cleanHref === null) {\n return text;\n }\n href = cleanHref;\n let out = `\"${text}\"`;\n {\n const tokens = genericToken[childTokens].flat(Infinity);\n values = values.concat(this.walkTokens(tokens, callback));\n });\n }\n else if (genericToken.tokens) {\n values = values.concat(this.walkTokens(genericToken.tokens, callback));\n }\n }\n }\n }\n return values;\n }\n use(...args) {\n const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };\n args.forEach((pack) => {\n // copy options to new object\n const opts = { ...pack };\n // set async to true if it was set to true before\n opts.async = this.defaults.async || opts.async || false;\n // ==-- Parse \"addon\" extensions --== //\n if (pack.extensions) {\n pack.extensions.forEach((ext) => {\n if (!ext.name) {\n throw new Error('extension name required');\n }\n if ('renderer' in ext) { // Renderer extensions\n const prevRenderer = extensions.renderers[ext.name];\n if (prevRenderer) {\n // Replace extension with func to run new extension but fall back if false\n extensions.renderers[ext.name] = function (...args) {\n let ret = ext.renderer.apply(this, args);\n if (ret === false) {\n ret = prevRenderer.apply(this, args);\n }\n return ret;\n };\n }\n else {\n extensions.renderers[ext.name] = ext.renderer;\n }\n }\n if ('tokenizer' in ext) { // Tokenizer Extensions\n if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {\n throw new Error(\"extension level must be 'block' or 'inline'\");\n }\n const extLevel = extensions[ext.level];\n if (extLevel) {\n extLevel.unshift(ext.tokenizer);\n }\n else {\n extensions[ext.level] = [ext.tokenizer];\n }\n if (ext.start) { // Function to check for start of token\n if (ext.level === 'block') {\n if (extensions.startBlock) {\n extensions.startBlock.push(ext.start);\n }\n else {\n extensions.startBlock = [ext.start];\n }\n }\n else if (ext.level === 'inline') {\n if (extensions.startInline) {\n extensions.startInline.push(ext.start);\n }\n else {\n extensions.startInline = [ext.start];\n }\n }\n }\n }\n if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens\n extensions.childTokens[ext.name] = ext.childTokens;\n }\n });\n opts.extensions = extensions;\n }\n // ==-- Parse \"overwrite\" extensions --== //\n if (pack.renderer) {\n const renderer = this.defaults.renderer || new _Renderer(this.defaults);\n for (const prop in pack.renderer) {\n if (!(prop in renderer)) {\n throw new Error(`renderer '${prop}' does not exist`);\n }\n if (['options', 'parser'].includes(prop)) {\n // ignore options property\n continue;\n }\n const rendererProp = prop;\n const rendererFunc = pack.renderer[rendererProp];\n const prevRenderer = renderer[rendererProp];\n // Replace renderer with func to run extension, but fall back if false\n renderer[rendererProp] = (...args) => {\n let ret = rendererFunc.apply(renderer, args);\n if (ret === false) {\n ret = prevRenderer.apply(renderer, args);\n }\n return ret || '';\n };\n }\n opts.renderer = renderer;\n }\n if (pack.tokenizer) {\n const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);\n for (const prop in pack.tokenizer) {\n if (!(prop in tokenizer)) {\n throw new Error(`tokenizer '${prop}' does not exist`);\n }\n if (['options', 'rules', 'lexer'].includes(prop)) {\n // ignore options, rules, and lexer properties\n continue;\n }\n const tokenizerProp = prop;\n const tokenizerFunc = pack.tokenizer[tokenizerProp];\n const prevTokenizer = tokenizer[tokenizerProp];\n // Replace tokenizer with func to run extension, but fall back if false\n // @ts-expect-error cannot type tokenizer function dynamically\n tokenizer[tokenizerProp] = (...args) => {\n let ret = tokenizerFunc.apply(tokenizer, args);\n if (ret === false) {\n ret = prevTokenizer.apply(tokenizer, args);\n }\n return ret;\n };\n }\n opts.tokenizer = tokenizer;\n }\n // ==-- Parse Hooks extensions --== //\n if (pack.hooks) {\n const hooks = this.defaults.hooks || new _Hooks();\n for (const prop in pack.hooks) {\n if (!(prop in hooks)) {\n throw new Error(`hook '${prop}' does not exist`);\n }\n if (['options', 'block'].includes(prop)) {\n // ignore options and block properties\n continue;\n }\n const hooksProp = prop;\n const hooksFunc = pack.hooks[hooksProp];\n const prevHook = hooks[hooksProp];\n if (_Hooks.passThroughHooks.has(prop)) {\n // @ts-expect-error cannot type hook function dynamically\n hooks[hooksProp] = (arg) => {\n if (this.defaults.async) {\n return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => {\n return prevHook.call(hooks, ret);\n });\n }\n const ret = hooksFunc.call(hooks, arg);\n return prevHook.call(hooks, ret);\n };\n }\n else {\n // @ts-expect-error cannot type hook function dynamically\n hooks[hooksProp] = (...args) => {\n let ret = hooksFunc.apply(hooks, args);\n if (ret === false) {\n ret = prevHook.apply(hooks, args);\n }\n return ret;\n };\n }\n }\n opts.hooks = hooks;\n }\n // ==-- Parse WalkTokens extensions --== //\n if (pack.walkTokens) {\n const walkTokens = this.defaults.walkTokens;\n const packWalktokens = pack.walkTokens;\n opts.walkTokens = function (token) {\n let values = [];\n values.push(packWalktokens.call(this, token));\n if (walkTokens) {\n values = values.concat(walkTokens.call(this, token));\n }\n return values;\n };\n }\n this.defaults = { ...this.defaults, ...opts };\n });\n return this;\n }\n setOptions(opt) {\n this.defaults = { ...this.defaults, ...opt };\n return this;\n }\n lexer(src, options) {\n return _Lexer.lex(src, options ?? this.defaults);\n }\n parser(tokens, options) {\n return _Parser.parse(tokens, options ?? this.defaults);\n }\n parseMarkdown(blockType) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const parse = (src, options) => {\n const origOpt = { ...options };\n const opt = { ...this.defaults, ...origOpt };\n const throwError = this.onError(!!opt.silent, !!opt.async);\n // throw error if an extension set async to true but parse was called with async: false\n if (this.defaults.async === true && origOpt.async === false) {\n return throwError(new Error('marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.'));\n }\n // throw error in case of non string input\n if (typeof src === 'undefined' || src === null) {\n return throwError(new Error('marked(): input parameter is undefined or null'));\n }\n if (typeof src !== 'string') {\n return throwError(new Error('marked(): input parameter is of type '\n + Object.prototype.toString.call(src) + ', string expected'));\n }\n if (opt.hooks) {\n opt.hooks.options = opt;\n opt.hooks.block = blockType;\n }\n const lexer = opt.hooks ? opt.hooks.provideLexer() : (blockType ? _Lexer.lex : _Lexer.lexInline);\n const parser = opt.hooks ? opt.hooks.provideParser() : (blockType ? _Parser.parse : _Parser.parseInline);\n if (opt.async) {\n return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)\n .then(src => lexer(src, opt))\n .then(tokens => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens)\n .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)\n .then(tokens => parser(tokens, opt))\n .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)\n .catch(throwError);\n }\n try {\n if (opt.hooks) {\n src = opt.hooks.preprocess(src);\n }\n let tokens = lexer(src, opt);\n if (opt.hooks) {\n tokens = opt.hooks.processAllTokens(tokens);\n }\n if (opt.walkTokens) {\n this.walkTokens(tokens, opt.walkTokens);\n }\n let html = parser(tokens, opt);\n if (opt.hooks) {\n html = opt.hooks.postprocess(html);\n }\n return html;\n }\n catch (e) {\n return throwError(e);\n }\n };\n return parse;\n }\n onError(silent, async) {\n return (e) => {\n e.message += '\\nPlease report this to https://github.com/markedjs/marked.';\n if (silent) {\n const msg = '

    An error occurred:

    '\n                    + escape(e.message + '', true)\n                    + '
    ';\n if (async) {\n return Promise.resolve(msg);\n }\n return msg;\n }\n if (async) {\n return Promise.reject(e);\n }\n throw e;\n };\n }\n}\n","import { _Lexer } from './Lexer.ts';\nimport { _Parser } from './Parser.ts';\nimport { _Tokenizer } from './Tokenizer.ts';\nimport { _Renderer } from './Renderer.ts';\nimport { _TextRenderer } from './TextRenderer.ts';\nimport { _Hooks } from './Hooks.ts';\nimport { Marked } from './Instance.ts';\nimport { _getDefaults, changeDefaults, _defaults, } from './defaults.ts';\nconst markedInstance = new Marked();\nexport function marked(src, opt) {\n return markedInstance.parse(src, opt);\n}\n/**\n * Sets the default options.\n *\n * @param options Hash of options\n */\nmarked.options =\n marked.setOptions = function (options) {\n markedInstance.setOptions(options);\n marked.defaults = markedInstance.defaults;\n changeDefaults(marked.defaults);\n return marked;\n };\n/**\n * Gets the original marked default options.\n */\nmarked.getDefaults = _getDefaults;\nmarked.defaults = _defaults;\n/**\n * Use Extension\n */\nmarked.use = function (...args) {\n markedInstance.use(...args);\n marked.defaults = markedInstance.defaults;\n changeDefaults(marked.defaults);\n return marked;\n};\n/**\n * Run callback for every token\n */\nmarked.walkTokens = function (tokens, callback) {\n return markedInstance.walkTokens(tokens, callback);\n};\n/**\n * Compiles markdown to HTML without enclosing `p` tag.\n *\n * @param src String of markdown source to be compiled\n * @param options Hash of options\n * @return String of compiled HTML\n */\nmarked.parseInline = markedInstance.parseInline;\n/**\n * Expose\n */\nmarked.Parser = _Parser;\nmarked.parser = _Parser.parse;\nmarked.Renderer = _Renderer;\nmarked.TextRenderer = _TextRenderer;\nmarked.Lexer = _Lexer;\nmarked.lexer = _Lexer.lex;\nmarked.Tokenizer = _Tokenizer;\nmarked.Hooks = _Hooks;\nmarked.parse = marked;\nexport const options = marked.options;\nexport const setOptions = marked.setOptions;\nexport const use = marked.use;\nexport const walkTokens = marked.walkTokens;\nexport const parseInline = marked.parseInline;\nexport const parse = marked;\nexport const parser = _Parser.parse;\nexport const lexer = _Lexer.lex;\nexport { _defaults as defaults, _getDefaults as getDefaults } from './defaults.ts';\nexport { _Lexer as Lexer } from './Lexer.ts';\nexport { _Parser as Parser } from './Parser.ts';\nexport { _Tokenizer as Tokenizer } from './Tokenizer.ts';\nexport { _Renderer as Renderer } from './Renderer.ts';\nexport { _TextRenderer as TextRenderer } from './TextRenderer.ts';\nexport { _Hooks as Hooks } from './Hooks.ts';\nexport { Marked } from './Instance.ts';\n"],"names":["_defaults","escape"],"mappings":"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"} \ No newline at end of file diff --git a/public/scripts/moment-min.js b/public/scripts/moment-min.js new file mode 100644 index 00000000..543e127f --- /dev/null +++ b/public/scripts/moment-min.js @@ -0,0 +1 @@ +!function(e,a){"object"==typeof exports&&"undefined"!=typeof module?module.exports=a():"function"==typeof define&&define.amd?define(a):e.moment=a()}(this,function(){"use strict";var E;function M(){return E.apply(null,arguments)}function F(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function z(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function l(e,a){return Object.prototype.hasOwnProperty.call(e,a)}function N(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;for(var a in e)if(l(e,a))return;return 1}function d(e){return void 0===e}function J(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function R(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function C(e,a){for(var t=[],s=e.length,n=0;n>>0,s=0;sBe(e)?(r=e+1,a-Be(e)):(r=e,a);return{year:r,dayOfYear:t}}function Xe(e,a,t){var s,n,r=$e(e.year(),a,t),r=Math.floor((e.dayOfYear()-r-1)/7)+1;return r<1?s=r+ea(n=e.year()-1,a,t):r>ea(e.year(),a,t)?(s=r-ea(e.year(),a,t),n=e.year()+1):(n=e.year(),s=r),{week:s,year:n}}function ea(e,a,t){var s=$e(e,a,t),a=$e(e+1,a,t);return(Be(e)-s+a)/7}s("w",["ww",2],"wo","week"),s("W",["WW",2],"Wo","isoWeek"),a("week","w"),a("isoWeek","W"),t("week",5),t("isoWeek",5),p("w",o),p("ww",o,r),p("W",o),p("WW",o,r),je(["w","ww","W","WW"],function(e,a,t,s){a[s.substr(0,1)]=m(e)});function aa(e,a){return e.slice(a,7).concat(e.slice(0,a))}s("d",0,"do","day"),s("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),s("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),s("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),s("e",0,0,"weekday"),s("E",0,0,"isoWeekday"),a("day","d"),a("weekday","e"),a("isoWeekday","E"),t("day",11),t("weekday",11),t("isoWeekday",11),p("d",o),p("e",o),p("E",o),p("dd",function(e,a){return a.weekdaysMinRegex(e)}),p("ddd",function(e,a){return a.weekdaysShortRegex(e)}),p("dddd",function(e,a){return a.weekdaysRegex(e)}),je(["dd","ddd","dddd"],function(e,a,t,s){s=t._locale.weekdaysParse(e,s,t._strict);null!=s?a.d=s:h(t).invalidWeekday=e}),je(["d","e","E"],function(e,a,t,s){a[s]=m(e)});var ta="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),sa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),na="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ra=f,da=f,ia=f;function _a(){function e(e,a){return a.length-e.length}for(var a,t,s,n=[],r=[],d=[],i=[],_=0;_<7;_++)s=U([2e3,1]).day(_),a=k(this.weekdaysMin(s,"")),t=k(this.weekdaysShort(s,"")),s=k(this.weekdays(s,"")),n.push(a),r.push(t),d.push(s),i.push(a),i.push(t),i.push(s);n.sort(e),r.sort(e),d.sort(e),i.sort(e),this._weekdaysRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+r.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+n.join("|")+")","i")}function oa(){return this.hours()%12||12}function ma(e,a){s(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),a)})}function ua(e,a){return a._meridiemParse}s("H",["HH",2],0,"hour"),s("h",["hh",2],0,oa),s("k",["kk",2],0,function(){return this.hours()||24}),s("hmm",0,0,function(){return""+oa.apply(this)+de(this.minutes(),2)}),s("hmmss",0,0,function(){return""+oa.apply(this)+de(this.minutes(),2)+de(this.seconds(),2)}),s("Hmm",0,0,function(){return""+this.hours()+de(this.minutes(),2)}),s("Hmmss",0,0,function(){return""+this.hours()+de(this.minutes(),2)+de(this.seconds(),2)}),ma("a",!0),ma("A",!1),a("hour","h"),t("hour",13),p("a",ua),p("A",ua),p("H",o),p("h",o),p("k",o),p("HH",o,r),p("hh",o,r),p("kk",o,r),p("hmm",c),p("hmmss",L),p("Hmm",c),p("Hmmss",L),D(["H","HH"],w),D(["k","kk"],function(e,a,t){e=m(e);a[w]=24===e?0:e}),D(["a","A"],function(e,a,t){t._isPm=t._locale.isPM(e),t._meridiem=e}),D(["h","hh"],function(e,a,t){a[w]=m(e),h(t).bigHour=!0}),D("hmm",function(e,a,t){var s=e.length-2;a[w]=m(e.substr(0,s)),a[Oe]=m(e.substr(s)),h(t).bigHour=!0}),D("hmmss",function(e,a,t){var s=e.length-4,n=e.length-2;a[w]=m(e.substr(0,s)),a[Oe]=m(e.substr(s,2)),a[We]=m(e.substr(n)),h(t).bigHour=!0}),D("Hmm",function(e,a,t){var s=e.length-2;a[w]=m(e.substr(0,s)),a[Oe]=m(e.substr(s))}),D("Hmmss",function(e,a,t){var s=e.length-4,n=e.length-2;a[w]=m(e.substr(0,s)),a[Oe]=m(e.substr(s,2)),a[We]=m(e.substr(n))});f=Ye("Hours",!0);var la,Ma={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Ne,monthsShort:Je,week:{dow:0,doy:6},weekdays:ta,weekdaysMin:na,weekdaysShort:sa,meridiemParse:/[ap]\.?m?\.?/i},b={},ha={};function ca(e){return e&&e.toLowerCase().replace("_","-")}function La(e){for(var a,t,s,n,r=0;r=a&&function(e,a){for(var t=Math.min(e.length,a.length),s=0;s=a-1)break;a--}r++}return la}function Ya(a){var e;if(void 0===b[a]&&"undefined"!=typeof module&&module&&module.exports&&null!=a.match("^[^/\\\\]*$"))try{e=la._abbr,require("./locale/"+a),ya(e)}catch(e){b[a]=null}return b[a]}function ya(e,a){return e&&((a=d(a)?pa(e):fa(e,a))?la=a:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),la._abbr}function fa(e,a){if(null===a)return delete b[e],null;var t,s=Ma;if(a.abbr=e,null!=b[e])ae("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=b[e]._config;else if(null!=a.parentLocale)if(null!=b[a.parentLocale])s=b[a.parentLocale]._config;else{if(null==(t=Ya(a.parentLocale)))return ha[a.parentLocale]||(ha[a.parentLocale]=[]),ha[a.parentLocale].push({name:e,config:a}),null;s=t._config}return b[e]=new ne(se(s,a)),ha[e]&&ha[e].forEach(function(e){fa(e.name,e.config)}),ya(e),b[e]}function pa(e){var a;if(!(e=e&&e._locale&&e._locale._abbr?e._locale._abbr:e))return la;if(!F(e)){if(a=Ya(e))return a;e=[e]}return La(e)}function ka(e){var a=e._a;return a&&-2===h(e).overflow&&(a=a[xe]<0||11ze(a[g],a[xe])?Pe:a[w]<0||24ea(r,_,o)?h(s)._overflowWeeks=!0:null!=m?h(s)._overflowWeekday=!0:(u=Qe(r,d,i,_,o),s._a[g]=u.year,s._dayOfYear=u.dayOfYear)),null!=e._dayOfYear&&(n=Oa(e._a[g],t[g]),(e._dayOfYear>Be(n)||0===e._dayOfYear)&&(h(e)._overflowDayOfYear=!0),m=Ze(n,0,e._dayOfYear),e._a[xe]=m.getUTCMonth(),e._a[Pe]=m.getUTCDate()),a=0;a<3&&null==e._a[a];++a)e._a[a]=l[a]=t[a];for(;a<7;a++)e._a[a]=l[a]=null==e._a[a]?2===a?1:0:e._a[a];24===e._a[w]&&0===e._a[Oe]&&0===e._a[We]&&0===e._a[Ae]&&(e._nextDay=!0,e._a[w]=0),e._d=(e._useUTC?Ze:qe).apply(null,l),r=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[w]=24),e._w&&void 0!==e._w.d&&e._w.d!==r&&(h(e).weekdayMismatch=!0)}}function Aa(e){if(e._f===M.ISO_8601)ja(e);else if(e._f===M.RFC_2822)Pa(e);else{e._a=[],h(e).empty=!0;for(var a,t,s,n,r,d=""+e._i,i=d.length,_=0,o=le(e._f,e._locale).match(ie)||[],m=o.length,u=0;ue.valueOf():e.valueOf()"}),n.toJSON=function(){return this.isValid()?this.toISOString():null},n.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},n.unix=function(){return Math.floor(this.valueOf()/1e3)},n.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},n.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},n.eraName=function(){for(var e,a=this.localeData().eras(),t=0,s=a.length;tthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},n.isLocal=function(){return!!this.isValid()&&!this._isUTC},n.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},n.isUtc=Ka,n.isUTC=Ka,n.zoneAbbr=function(){return this._isUTC?"UTC":""},n.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},n.dates=e("dates accessor is deprecated. Use date instead.",Y),n.months=e("months accessor is deprecated. Use month instead",Ge),n.years=e("years accessor is deprecated. Use year instead",Ke),n.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,a){return null!=e?(this.utcOffset(e="string"!=typeof e?-e:e,a),this):-this.utcOffset()}),n.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!d(this._isDSTShifted))return this._isDSTShifted;var e,a={};return Z(a,this),(a=Ea(a))._a?(e=(a._isUTC?U:S)(a._a),this._isDSTShifted=this.isValid()&&0>> 0, + i; + + for (i = 0; i < len; i++) { + if (i in t && fun.call(this, t[i], i, t)) { + return true; + } + } + + return false; + }; + } + + function isValid(m) { + if (m._isValid == null) { + var flags = getParsingFlags(m), + parsedParts = some.call(flags.parsedDateParts, function (i) { + return i != null; + }), + isNowValid = + !isNaN(m._d.getTime()) && + flags.overflow < 0 && + !flags.empty && + !flags.invalidEra && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.weekdayMismatch && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated && + (!flags.meridiem || (flags.meridiem && parsedParts)); + + if (m._strict) { + isNowValid = + isNowValid && + flags.charsLeftOver === 0 && + flags.unusedTokens.length === 0 && + flags.bigHour === undefined; + } + + if (Object.isFrozen == null || !Object.isFrozen(m)) { + m._isValid = isNowValid; + } else { + return isNowValid; + } + } + return m._isValid; + } + + function createInvalid(flags) { + var m = createUTC(NaN); + if (flags != null) { + extend(getParsingFlags(m), flags); + } else { + getParsingFlags(m).userInvalidated = true; + } + + return m; + } + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + var momentProperties = (hooks.momentProperties = []), + updateInProgress = false; + + function copyConfig(to, from) { + var i, + prop, + val, + momentPropertiesLen = momentProperties.length; + + if (!isUndefined(from._isAMomentObject)) { + to._isAMomentObject = from._isAMomentObject; + } + if (!isUndefined(from._i)) { + to._i = from._i; + } + if (!isUndefined(from._f)) { + to._f = from._f; + } + if (!isUndefined(from._l)) { + to._l = from._l; + } + if (!isUndefined(from._strict)) { + to._strict = from._strict; + } + if (!isUndefined(from._tzm)) { + to._tzm = from._tzm; + } + if (!isUndefined(from._isUTC)) { + to._isUTC = from._isUTC; + } + if (!isUndefined(from._offset)) { + to._offset = from._offset; + } + if (!isUndefined(from._pf)) { + to._pf = getParsingFlags(from); + } + if (!isUndefined(from._locale)) { + to._locale = from._locale; + } + + if (momentPropertiesLen > 0) { + for (i = 0; i < momentPropertiesLen; i++) { + prop = momentProperties[i]; + val = from[prop]; + if (!isUndefined(val)) { + to[prop] = val; + } + } + } + + return to; + } + + // Moment prototype object + function Moment(config) { + copyConfig(this, config); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); + if (!this.isValid()) { + this._d = new Date(NaN); + } + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + hooks.updateOffset(this); + updateInProgress = false; + } + } + + function isMoment(obj) { + return ( + obj instanceof Moment || (obj != null && obj._isAMomentObject != null) + ); + } + + function warn(msg) { + if ( + hooks.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && + console.warn + ) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + + return extend(function () { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(null, msg); + } + if (firstTime) { + var args = [], + arg, + i, + key, + argLen = arguments.length; + for (i = 0; i < argLen; i++) { + arg = ''; + if (typeof arguments[i] === 'object') { + arg += '\n[' + i + '] '; + for (key in arguments[0]) { + if (hasOwnProp(arguments[0], key)) { + arg += key + ': ' + arguments[0][key] + ', '; + } + } + arg = arg.slice(0, -2); // Remove trailing comma and space + } else { + arg = arguments[i]; + } + args.push(arg); + } + warn( + msg + + '\nArguments: ' + + Array.prototype.slice.call(args).join('') + + '\n' + + new Error().stack + ); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + var deprecations = {}; + + function deprecateSimple(name, msg) { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(name, msg); + } + if (!deprecations[name]) { + warn(msg); + deprecations[name] = true; + } + } + + hooks.suppressDeprecationWarnings = false; + hooks.deprecationHandler = null; + + function isFunction(input) { + return ( + (typeof Function !== 'undefined' && input instanceof Function) || + Object.prototype.toString.call(input) === '[object Function]' + ); + } + + function set(config) { + var prop, i; + for (i in config) { + if (hasOwnProp(config, i)) { + prop = config[i]; + if (isFunction(prop)) { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + } + this._config = config; + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _dayOfMonthOrdinalParse. + // TODO: Remove "ordinalParse" fallback in next major release. + this._dayOfMonthOrdinalParseLenient = new RegExp( + (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + + '|' + + /\d{1,2}/.source + ); + } + + function mergeConfigs(parentConfig, childConfig) { + var res = extend({}, parentConfig), + prop; + for (prop in childConfig) { + if (hasOwnProp(childConfig, prop)) { + if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { + res[prop] = {}; + extend(res[prop], parentConfig[prop]); + extend(res[prop], childConfig[prop]); + } else if (childConfig[prop] != null) { + res[prop] = childConfig[prop]; + } else { + delete res[prop]; + } + } + } + for (prop in parentConfig) { + if ( + hasOwnProp(parentConfig, prop) && + !hasOwnProp(childConfig, prop) && + isObject(parentConfig[prop]) + ) { + // make sure changes to properties don't modify parent config + res[prop] = extend({}, res[prop]); + } + } + return res; + } + + function Locale(config) { + if (config != null) { + this.set(config); + } + } + + var keys; + + if (Object.keys) { + keys = Object.keys; + } else { + keys = function (obj) { + var i, + res = []; + for (i in obj) { + if (hasOwnProp(obj, i)) { + res.push(i); + } + } + return res; + }; + } + + var defaultCalendar = { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }; + + function calendar(key, mom, now) { + var output = this._calendar[key] || this._calendar['sameElse']; + return isFunction(output) ? output.call(mom, now) : output; + } + + function zeroFill(number, targetLength, forceSign) { + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, + sign = number >= 0; + return ( + (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + + absNumber + ); + } + + var formattingTokens = + /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, + formatFunctions = {}, + formatTokenFunctions = {}; + + // token: 'M' + // padded: ['MM', 2] + // ordinal: 'Mo' + // callback: function () { this.month() + 1 } + function addFormatToken(token, padded, ordinal, callback) { + var func = callback; + if (typeof callback === 'string') { + func = function () { + return this[callback](); + }; + } + if (token) { + formatTokenFunctions[token] = func; + } + if (padded) { + formatTokenFunctions[padded[0]] = function () { + return zeroFill(func.apply(this, arguments), padded[1], padded[2]); + }; + } + if (ordinal) { + formatTokenFunctions[ordinal] = function () { + return this.localeData().ordinal( + func.apply(this, arguments), + token + ); + }; + } + } + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), + i, + length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = '', + i; + for (i = 0; i < length; i++) { + output += isFunction(array[i]) + ? array[i].call(mom, format) + : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + formatFunctions[format] = + formatFunctions[format] || makeFormatFunction(format); + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace( + localFormattingTokens, + replaceLongDateFormatTokens + ); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + var defaultLongDateFormat = { + LTS: 'h:mm:ss A', + LT: 'h:mm A', + L: 'MM/DD/YYYY', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY h:mm A', + LLLL: 'dddd, MMMM D, YYYY h:mm A', + }; + + function longDateFormat(key) { + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + this._longDateFormat[key] = formatUpper + .match(formattingTokens) + .map(function (tok) { + if ( + tok === 'MMMM' || + tok === 'MM' || + tok === 'DD' || + tok === 'dddd' + ) { + return tok.slice(1); + } + return tok; + }) + .join(''); + + return this._longDateFormat[key]; + } + + var defaultInvalidDate = 'Invalid date'; + + function invalidDate() { + return this._invalidDate; + } + + var defaultOrdinal = '%d', + defaultDayOfMonthOrdinalParse = /\d{1,2}/; + + function ordinal(number) { + return this._ordinal.replace('%d', number); + } + + var defaultRelativeTime = { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + w: 'a week', + ww: '%d weeks', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }; + + function relativeTime(number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return isFunction(output) + ? output(number, withoutSuffix, string, isFuture) + : output.replace(/%d/i, number); + } + + function pastFuture(diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return isFunction(format) ? format(output) : format.replace(/%s/i, output); + } + + var aliases = {}; + + function addUnitAlias(unit, shorthand) { + var lowerCase = unit.toLowerCase(); + aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; + } + + function normalizeUnits(units) { + return typeof units === 'string' + ? aliases[units] || aliases[units.toLowerCase()] + : undefined; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + var priorities = {}; + + function addUnitPriority(unit, priority) { + priorities[unit] = priority; + } + + function getPrioritizedUnits(unitsObj) { + var units = [], + u; + for (u in unitsObj) { + if (hasOwnProp(unitsObj, u)) { + units.push({ unit: u, priority: priorities[u] }); + } + } + units.sort(function (a, b) { + return a.priority - b.priority; + }); + return units; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function absFloor(number) { + if (number < 0) { + // -0 -> 0 + return Math.ceil(number) || 0; + } else { + return Math.floor(number); + } + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; + } + + function makeGetSet(unit, keepTime) { + return function (value) { + if (value != null) { + set$1(this, unit, value); + hooks.updateOffset(this, keepTime); + return this; + } else { + return get(this, unit); + } + }; + } + + function get(mom, unit) { + return mom.isValid() + ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() + : NaN; + } + + function set$1(mom, unit, value) { + if (mom.isValid() && !isNaN(value)) { + if ( + unit === 'FullYear' && + isLeapYear(mom.year()) && + mom.month() === 1 && + mom.date() === 29 + ) { + value = toInt(value); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit]( + value, + mom.month(), + daysInMonth(value, mom.month()) + ); + } else { + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + } + + // MOMENTS + + function stringGet(units) { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](); + } + return this; + } + + function stringSet(units, value) { + if (typeof units === 'object') { + units = normalizeObjectUnits(units); + var prioritized = getPrioritizedUnits(units), + i, + prioritizedLen = prioritized.length; + for (i = 0; i < prioritizedLen; i++) { + this[prioritized[i].unit](units[prioritized[i].unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; + } + + var match1 = /\d/, // 0 - 9 + match2 = /\d\d/, // 00 - 99 + match3 = /\d{3}/, // 000 - 999 + match4 = /\d{4}/, // 0000 - 9999 + match6 = /[+-]?\d{6}/, // -999999 - 999999 + match1to2 = /\d\d?/, // 0 - 99 + match3to4 = /\d\d\d\d?/, // 999 - 9999 + match5to6 = /\d\d\d\d\d\d?/, // 99999 - 999999 + match1to3 = /\d{1,3}/, // 0 - 999 + match1to4 = /\d{1,4}/, // 0 - 9999 + match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999 + matchUnsigned = /\d+/, // 0 - inf + matchSigned = /[+-]?\d+/, // -inf - inf + matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z + matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + // any word (or two) characters or numbers including two/three word month in arabic. + // includes scottish gaelic two word and hyphenated months + matchWord = + /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, + regexes; + + regexes = {}; + + function addRegexToken(token, regex, strictRegex) { + regexes[token] = isFunction(regex) + ? regex + : function (isStrict, localeData) { + return isStrict && strictRegex ? strictRegex : regex; + }; + } + + function getParseRegexForToken(token, config) { + if (!hasOwnProp(regexes, token)) { + return new RegExp(unescapeFormat(token)); + } + + return regexes[token](config._strict, config._locale); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function unescapeFormat(s) { + return regexEscape( + s + .replace('\\', '') + .replace( + /\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, + function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + } + ) + ); + } + + function regexEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + var tokens = {}; + + function addParseToken(token, callback) { + var i, + func = callback, + tokenLen; + if (typeof token === 'string') { + token = [token]; + } + if (isNumber(callback)) { + func = function (input, array) { + array[callback] = toInt(input); + }; + } + tokenLen = token.length; + for (i = 0; i < tokenLen; i++) { + tokens[token[i]] = func; + } + } + + function addWeekParseToken(token, callback) { + addParseToken(token, function (input, array, config, token) { + config._w = config._w || {}; + callback(input, config._w, config, token); + }); + } + + function addTimeToArrayFromToken(token, input, config) { + if (input != null && hasOwnProp(tokens, token)) { + tokens[token](input, config._a, config, token); + } + } + + var YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + WEEK = 7, + WEEKDAY = 8; + + function mod(n, x) { + return ((n % x) + x) % x; + } + + var indexOf; + + if (Array.prototype.indexOf) { + indexOf = Array.prototype.indexOf; + } else { + indexOf = function (o) { + // I know + var i; + for (i = 0; i < this.length; ++i) { + if (this[i] === o) { + return i; + } + } + return -1; + }; + } + + function daysInMonth(year, month) { + if (isNaN(year) || isNaN(month)) { + return NaN; + } + var modMonth = mod(month, 12); + year += (month - modMonth) / 12; + return modMonth === 1 + ? isLeapYear(year) + ? 29 + : 28 + : 31 - ((modMonth % 7) % 2); + } + + // FORMATTING + + addFormatToken('M', ['MM', 2], 'Mo', function () { + return this.month() + 1; + }); + + addFormatToken('MMM', 0, 0, function (format) { + return this.localeData().monthsShort(this, format); + }); + + addFormatToken('MMMM', 0, 0, function (format) { + return this.localeData().months(this, format); + }); + + // ALIASES + + addUnitAlias('month', 'M'); + + // PRIORITY + + addUnitPriority('month', 8); + + // PARSING + + addRegexToken('M', match1to2); + addRegexToken('MM', match1to2, match2); + addRegexToken('MMM', function (isStrict, locale) { + return locale.monthsShortRegex(isStrict); + }); + addRegexToken('MMMM', function (isStrict, locale) { + return locale.monthsRegex(isStrict); + }); + + addParseToken(['M', 'MM'], function (input, array) { + array[MONTH] = toInt(input) - 1; + }); + + addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { + var month = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (month != null) { + array[MONTH] = month; + } else { + getParsingFlags(config).invalidMonth = input; + } + }); + + // LOCALES + + var defaultLocaleMonths = + 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + defaultLocaleMonthsShort = + 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, + defaultMonthsShortRegex = matchWord, + defaultMonthsRegex = matchWord; + + function localeMonths(m, format) { + if (!m) { + return isArray(this._months) + ? this._months + : this._months['standalone']; + } + return isArray(this._months) + ? this._months[m.month()] + : this._months[ + (this._months.isFormat || MONTHS_IN_FORMAT).test(format) + ? 'format' + : 'standalone' + ][m.month()]; + } + + function localeMonthsShort(m, format) { + if (!m) { + return isArray(this._monthsShort) + ? this._monthsShort + : this._monthsShort['standalone']; + } + return isArray(this._monthsShort) + ? this._monthsShort[m.month()] + : this._monthsShort[ + MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone' + ][m.month()]; + } + + function handleStrictParse(monthName, format, strict) { + var i, + ii, + mom, + llc = monthName.toLocaleLowerCase(); + if (!this._monthsParse) { + // this is not used + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + for (i = 0; i < 12; ++i) { + mom = createUTC([2000, i]); + this._shortMonthsParse[i] = this.monthsShort( + mom, + '' + ).toLocaleLowerCase(); + this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'MMM') { + ii = indexOf.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'MMM') { + ii = indexOf.call(this._shortMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._longMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } + } + + function localeMonthsParse(monthName, format, strict) { + var i, mom, regex; + + if (this._monthsParseExact) { + return handleStrictParse.call(this, monthName, format, strict); + } + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + // TODO: add sorting + // Sorting makes sure if one month (or abbr) is a prefix of another + // see sorting in computeMonthsParse + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp( + '^' + this.months(mom, '').replace('.', '') + '$', + 'i' + ); + this._shortMonthsParse[i] = new RegExp( + '^' + this.monthsShort(mom, '').replace('.', '') + '$', + 'i' + ); + } + if (!strict && !this._monthsParse[i]) { + regex = + '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if ( + strict && + format === 'MMMM' && + this._longMonthsParse[i].test(monthName) + ) { + return i; + } else if ( + strict && + format === 'MMM' && + this._shortMonthsParse[i].test(monthName) + ) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + } + + // MOMENTS + + function setMonth(mom, value) { + var dayOfMonth; + + if (!mom.isValid()) { + // No op + return mom; + } + + if (typeof value === 'string') { + if (/^\d+$/.test(value)) { + value = toInt(value); + } else { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (!isNumber(value)) { + return mom; + } + } + } + + dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function getSetMonth(value) { + if (value != null) { + setMonth(this, value); + hooks.updateOffset(this, true); + return this; + } else { + return get(this, 'Month'); + } + } + + function getDaysInMonth() { + return daysInMonth(this.year(), this.month()); + } + + function monthsShortRegex(isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsShortStrictRegex; + } else { + return this._monthsShortRegex; + } + } else { + if (!hasOwnProp(this, '_monthsShortRegex')) { + this._monthsShortRegex = defaultMonthsShortRegex; + } + return this._monthsShortStrictRegex && isStrict + ? this._monthsShortStrictRegex + : this._monthsShortRegex; + } + } + + function monthsRegex(isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsStrictRegex; + } else { + return this._monthsRegex; + } + } else { + if (!hasOwnProp(this, '_monthsRegex')) { + this._monthsRegex = defaultMonthsRegex; + } + return this._monthsStrictRegex && isStrict + ? this._monthsStrictRegex + : this._monthsRegex; + } + } + + function computeMonthsParse() { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var shortPieces = [], + longPieces = [], + mixedPieces = [], + i, + mom; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + shortPieces.push(this.monthsShort(mom, '')); + longPieces.push(this.months(mom, '')); + mixedPieces.push(this.months(mom, '')); + mixedPieces.push(this.monthsShort(mom, '')); + } + // Sorting makes sure if one month (or abbr) is a prefix of another it + // will match the longer piece. + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 12; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + } + for (i = 0; i < 24; i++) { + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._monthsShortRegex = this._monthsRegex; + this._monthsStrictRegex = new RegExp( + '^(' + longPieces.join('|') + ')', + 'i' + ); + this._monthsShortStrictRegex = new RegExp( + '^(' + shortPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? zeroFill(y, 4) : '+' + y; + }); + + addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; + }); + + addFormatToken(0, ['YYYY', 4], 0, 'year'); + addFormatToken(0, ['YYYYY', 5], 0, 'year'); + addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + + // ALIASES + + addUnitAlias('year', 'y'); + + // PRIORITIES + + addUnitPriority('year', 1); + + // PARSING + + addRegexToken('Y', matchSigned); + addRegexToken('YY', match1to2, match2); + addRegexToken('YYYY', match1to4, match4); + addRegexToken('YYYYY', match1to6, match6); + addRegexToken('YYYYYY', match1to6, match6); + + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = + input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); + }); + addParseToken('YY', function (input, array) { + array[YEAR] = hooks.parseTwoDigitYear(input); + }); + addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); + }); + + // HELPERS + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + // HOOKS + + hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + // MOMENTS + + var getSetYear = makeGetSet('FullYear', true); + + function getIsLeapYear() { + return isLeapYear(this.year()); + } + + function createDate(y, m, d, h, M, s, ms) { + // can't just apply() to create a date: + // https://stackoverflow.com/q/181348 + var date; + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + date = new Date(y + 400, m, d, h, M, s, ms); + if (isFinite(date.getFullYear())) { + date.setFullYear(y); + } + } else { + date = new Date(y, m, d, h, M, s, ms); + } + + return date; + } + + function createUTCDate(y) { + var date, args; + // the Date.UTC function remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + args = Array.prototype.slice.call(arguments); + // preserve leap years using a full 400 year cycle, then reset + args[0] = y + 400; + date = new Date(Date.UTC.apply(null, args)); + if (isFinite(date.getUTCFullYear())) { + date.setUTCFullYear(y); + } + } else { + date = new Date(Date.UTC.apply(null, arguments)); + } + + return date; + } + + // start-of-first-week - start-of-year + function firstWeekOffset(year, dow, doy) { + var // first-week day -- which january is always in the first week (4 for iso, 1 for other) + fwd = 7 + dow - doy, + // first-week day local weekday -- which local weekday is fwd + fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + + return -fwdlw + fwd - 1; + } + + // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, dow, doy) { + var localWeekday = (7 + weekday - dow) % 7, + weekOffset = firstWeekOffset(year, dow, doy), + dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, + resYear, + resDayOfYear; + + if (dayOfYear <= 0) { + resYear = year - 1; + resDayOfYear = daysInYear(resYear) + dayOfYear; + } else if (dayOfYear > daysInYear(year)) { + resYear = year + 1; + resDayOfYear = dayOfYear - daysInYear(year); + } else { + resYear = year; + resDayOfYear = dayOfYear; + } + + return { + year: resYear, + dayOfYear: resDayOfYear, + }; + } + + function weekOfYear(mom, dow, doy) { + var weekOffset = firstWeekOffset(mom.year(), dow, doy), + week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, + resWeek, + resYear; + + if (week < 1) { + resYear = mom.year() - 1; + resWeek = week + weeksInYear(resYear, dow, doy); + } else if (week > weeksInYear(mom.year(), dow, doy)) { + resWeek = week - weeksInYear(mom.year(), dow, doy); + resYear = mom.year() + 1; + } else { + resYear = mom.year(); + resWeek = week; + } + + return { + week: resWeek, + year: resYear, + }; + } + + function weeksInYear(year, dow, doy) { + var weekOffset = firstWeekOffset(year, dow, doy), + weekOffsetNext = firstWeekOffset(year + 1, dow, doy); + return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; + } + + // FORMATTING + + addFormatToken('w', ['ww', 2], 'wo', 'week'); + addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); + + // ALIASES + + addUnitAlias('week', 'w'); + addUnitAlias('isoWeek', 'W'); + + // PRIORITIES + + addUnitPriority('week', 5); + addUnitPriority('isoWeek', 5); + + // PARSING + + addRegexToken('w', match1to2); + addRegexToken('ww', match1to2, match2); + addRegexToken('W', match1to2); + addRegexToken('WW', match1to2, match2); + + addWeekParseToken( + ['w', 'ww', 'W', 'WW'], + function (input, week, config, token) { + week[token.substr(0, 1)] = toInt(input); + } + ); + + // HELPERS + + // LOCALES + + function localeWeek(mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + } + + var defaultLocaleWeek = { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }; + + function localeFirstDayOfWeek() { + return this._week.dow; + } + + function localeFirstDayOfYear() { + return this._week.doy; + } + + // MOMENTS + + function getSetWeek(input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + function getSetISOWeek(input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + } + + // FORMATTING + + addFormatToken('d', 0, 'do', 'day'); + + addFormatToken('dd', 0, 0, function (format) { + return this.localeData().weekdaysMin(this, format); + }); + + addFormatToken('ddd', 0, 0, function (format) { + return this.localeData().weekdaysShort(this, format); + }); + + addFormatToken('dddd', 0, 0, function (format) { + return this.localeData().weekdays(this, format); + }); + + addFormatToken('e', 0, 0, 'weekday'); + addFormatToken('E', 0, 0, 'isoWeekday'); + + // ALIASES + + addUnitAlias('day', 'd'); + addUnitAlias('weekday', 'e'); + addUnitAlias('isoWeekday', 'E'); + + // PRIORITY + addUnitPriority('day', 11); + addUnitPriority('weekday', 11); + addUnitPriority('isoWeekday', 11); + + // PARSING + + addRegexToken('d', match1to2); + addRegexToken('e', match1to2); + addRegexToken('E', match1to2); + addRegexToken('dd', function (isStrict, locale) { + return locale.weekdaysMinRegex(isStrict); + }); + addRegexToken('ddd', function (isStrict, locale) { + return locale.weekdaysShortRegex(isStrict); + }); + addRegexToken('dddd', function (isStrict, locale) { + return locale.weekdaysRegex(isStrict); + }); + + addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { + var weekday = config._locale.weekdaysParse(input, token, config._strict); + // if we didn't get a weekday name, mark the date as invalid + if (weekday != null) { + week.d = weekday; + } else { + getParsingFlags(config).invalidWeekday = input; + } + }); + + addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { + week[token] = toInt(input); + }); + + // HELPERS + + function parseWeekday(input, locale) { + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; + } + + return null; + } + + function parseIsoWeekday(input, locale) { + if (typeof input === 'string') { + return locale.weekdaysParse(input) % 7 || 7; + } + return isNaN(input) ? null : input; + } + + // LOCALES + function shiftWeekdays(ws, n) { + return ws.slice(n, 7).concat(ws.slice(0, n)); + } + + var defaultLocaleWeekdays = + 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + defaultWeekdaysRegex = matchWord, + defaultWeekdaysShortRegex = matchWord, + defaultWeekdaysMinRegex = matchWord; + + function localeWeekdays(m, format) { + var weekdays = isArray(this._weekdays) + ? this._weekdays + : this._weekdays[ + m && m !== true && this._weekdays.isFormat.test(format) + ? 'format' + : 'standalone' + ]; + return m === true + ? shiftWeekdays(weekdays, this._week.dow) + : m + ? weekdays[m.day()] + : weekdays; + } + + function localeWeekdaysShort(m) { + return m === true + ? shiftWeekdays(this._weekdaysShort, this._week.dow) + : m + ? this._weekdaysShort[m.day()] + : this._weekdaysShort; + } + + function localeWeekdaysMin(m) { + return m === true + ? shiftWeekdays(this._weekdaysMin, this._week.dow) + : m + ? this._weekdaysMin[m.day()] + : this._weekdaysMin; + } + + function handleStrictParse$1(weekdayName, format, strict) { + var i, + ii, + mom, + llc = weekdayName.toLocaleLowerCase(); + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._shortWeekdaysParse = []; + this._minWeekdaysParse = []; + + for (i = 0; i < 7; ++i) { + mom = createUTC([2000, 1]).day(i); + this._minWeekdaysParse[i] = this.weekdaysMin( + mom, + '' + ).toLocaleLowerCase(); + this._shortWeekdaysParse[i] = this.weekdaysShort( + mom, + '' + ).toLocaleLowerCase(); + this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'dddd') { + ii = indexOf.call(this._weekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'dddd') { + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf.call(this._minWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } + } + + function localeWeekdaysParse(weekdayName, format, strict) { + var i, mom, regex; + + if (this._weekdaysParseExact) { + return handleStrictParse$1.call(this, weekdayName, format, strict); + } + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._minWeekdaysParse = []; + this._shortWeekdaysParse = []; + this._fullWeekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + + mom = createUTC([2000, 1]).day(i); + if (strict && !this._fullWeekdaysParse[i]) { + this._fullWeekdaysParse[i] = new RegExp( + '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + this._shortWeekdaysParse[i] = new RegExp( + '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + this._minWeekdaysParse[i] = new RegExp( + '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', + 'i' + ); + } + if (!this._weekdaysParse[i]) { + regex = + '^' + + this.weekdays(mom, '') + + '|^' + + this.weekdaysShort(mom, '') + + '|^' + + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if ( + strict && + format === 'dddd' && + this._fullWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if ( + strict && + format === 'ddd' && + this._shortWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if ( + strict && + format === 'dd' && + this._minWeekdaysParse[i].test(weekdayName) + ) { + return i; + } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + } + + // MOMENTS + + function getSetDayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + } + + function getSetLocaleDayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + } + + function getSetISODayOfWeek(input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + + if (input != null) { + var weekday = parseIsoWeekday(input, this.localeData()); + return this.day(this.day() % 7 ? weekday : weekday - 7); + } else { + return this.day() || 7; + } + } + + function weekdaysRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysStrictRegex; + } else { + return this._weekdaysRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysRegex')) { + this._weekdaysRegex = defaultWeekdaysRegex; + } + return this._weekdaysStrictRegex && isStrict + ? this._weekdaysStrictRegex + : this._weekdaysRegex; + } + } + + function weekdaysShortRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysShortStrictRegex; + } else { + return this._weekdaysShortRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysShortRegex')) { + this._weekdaysShortRegex = defaultWeekdaysShortRegex; + } + return this._weekdaysShortStrictRegex && isStrict + ? this._weekdaysShortStrictRegex + : this._weekdaysShortRegex; + } + } + + function weekdaysMinRegex(isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysMinStrictRegex; + } else { + return this._weekdaysMinRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysMinRegex')) { + this._weekdaysMinRegex = defaultWeekdaysMinRegex; + } + return this._weekdaysMinStrictRegex && isStrict + ? this._weekdaysMinStrictRegex + : this._weekdaysMinRegex; + } + } + + function computeWeekdaysParse() { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var minPieces = [], + shortPieces = [], + longPieces = [], + mixedPieces = [], + i, + mom, + minp, + shortp, + longp; + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, 1]).day(i); + minp = regexEscape(this.weekdaysMin(mom, '')); + shortp = regexEscape(this.weekdaysShort(mom, '')); + longp = regexEscape(this.weekdays(mom, '')); + minPieces.push(minp); + shortPieces.push(shortp); + longPieces.push(longp); + mixedPieces.push(minp); + mixedPieces.push(shortp); + mixedPieces.push(longp); + } + // Sorting makes sure if one weekday (or abbr) is a prefix of another it + // will match the longer piece. + minPieces.sort(cmpLenRev); + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + + this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._weekdaysShortRegex = this._weekdaysRegex; + this._weekdaysMinRegex = this._weekdaysRegex; + + this._weekdaysStrictRegex = new RegExp( + '^(' + longPieces.join('|') + ')', + 'i' + ); + this._weekdaysShortStrictRegex = new RegExp( + '^(' + shortPieces.join('|') + ')', + 'i' + ); + this._weekdaysMinStrictRegex = new RegExp( + '^(' + minPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + function hFormat() { + return this.hours() % 12 || 12; + } + + function kFormat() { + return this.hours() || 24; + } + + addFormatToken('H', ['HH', 2], 0, 'hour'); + addFormatToken('h', ['hh', 2], 0, hFormat); + addFormatToken('k', ['kk', 2], 0, kFormat); + + addFormatToken('hmm', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); + }); + + addFormatToken('hmmss', 0, 0, function () { + return ( + '' + + hFormat.apply(this) + + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2) + ); + }); + + addFormatToken('Hmm', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2); + }); + + addFormatToken('Hmmss', 0, 0, function () { + return ( + '' + + this.hours() + + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2) + ); + }); + + function meridiem(token, lowercase) { + addFormatToken(token, 0, 0, function () { + return this.localeData().meridiem( + this.hours(), + this.minutes(), + lowercase + ); + }); + } + + meridiem('a', true); + meridiem('A', false); + + // ALIASES + + addUnitAlias('hour', 'h'); + + // PRIORITY + addUnitPriority('hour', 13); + + // PARSING + + function matchMeridiem(isStrict, locale) { + return locale._meridiemParse; + } + + addRegexToken('a', matchMeridiem); + addRegexToken('A', matchMeridiem); + addRegexToken('H', match1to2); + addRegexToken('h', match1to2); + addRegexToken('k', match1to2); + addRegexToken('HH', match1to2, match2); + addRegexToken('hh', match1to2, match2); + addRegexToken('kk', match1to2, match2); + + addRegexToken('hmm', match3to4); + addRegexToken('hmmss', match5to6); + addRegexToken('Hmm', match3to4); + addRegexToken('Hmmss', match5to6); + + addParseToken(['H', 'HH'], HOUR); + addParseToken(['k', 'kk'], function (input, array, config) { + var kInput = toInt(input); + array[HOUR] = kInput === 24 ? 0 : kInput; + }); + addParseToken(['a', 'A'], function (input, array, config) { + config._isPm = config._locale.isPM(input); + config._meridiem = input; + }); + addParseToken(['h', 'hh'], function (input, array, config) { + array[HOUR] = toInt(input); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('hmmss', function (input, array, config) { + var pos1 = input.length - 4, + pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + getParsingFlags(config).bigHour = true; + }); + addParseToken('Hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + }); + addParseToken('Hmmss', function (input, array, config) { + var pos1 = input.length - 4, + pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + }); + + // LOCALES + + function localeIsPM(input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return (input + '').toLowerCase().charAt(0) === 'p'; + } + + var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i, + // Setting the hour should keep the time, because the user explicitly + // specified which hour they want. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + getSetHour = makeGetSet('Hours', true); + + function localeMeridiem(hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + } + + var baseConfig = { + calendar: defaultCalendar, + longDateFormat: defaultLongDateFormat, + invalidDate: defaultInvalidDate, + ordinal: defaultOrdinal, + dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, + relativeTime: defaultRelativeTime, + + months: defaultLocaleMonths, + monthsShort: defaultLocaleMonthsShort, + + week: defaultLocaleWeek, + + weekdays: defaultLocaleWeekdays, + weekdaysMin: defaultLocaleWeekdaysMin, + weekdaysShort: defaultLocaleWeekdaysShort, + + meridiemParse: defaultLocaleMeridiemParse, + }; + + // internal storage for locale config files + var locales = {}, + localeFamilies = {}, + globalLocale; + + function commonPrefix(arr1, arr2) { + var i, + minl = Math.min(arr1.length, arr2.length); + for (i = 0; i < minl; i += 1) { + if (arr1[i] !== arr2[i]) { + return i; + } + } + return minl; + } + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, + j, + next, + locale, + split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if ( + next && + next.length >= j && + commonPrefix(split, next) >= j - 1 + ) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return globalLocale; + } + + function isLocaleNameSane(name) { + // Prevent names that look like filesystem paths, i.e contain '/' or '\' + return name.match('^[^/\\\\]*$') != null; + } + + function loadLocale(name) { + var oldLocale = null, + aliasedRequire; + // TODO: Find a better way to register and load all the locales in Node + if ( + locales[name] === undefined && + typeof module !== 'undefined' && + module && + module.exports && + isLocaleNameSane(name) + ) { + try { + oldLocale = globalLocale._abbr; + aliasedRequire = require; + aliasedRequire('./locale/' + name); + getSetGlobalLocale(oldLocale); + } catch (e) { + // mark as not found to avoid repeating expensive file require call causing high CPU + // when trying to find en-US, en_US, en-us for every format call + locales[name] = null; // null means not found + } + } + return locales[name]; + } + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + function getSetGlobalLocale(key, values) { + var data; + if (key) { + if (isUndefined(values)) { + data = getLocale(key); + } else { + data = defineLocale(key, values); + } + + if (data) { + // moment.duration._locale = moment._locale = data; + globalLocale = data; + } else { + if (typeof console !== 'undefined' && console.warn) { + //warn user if arguments are passed but the locale could not be set + console.warn( + 'Locale ' + key + ' not found. Did you forget to load it?' + ); + } + } + } + + return globalLocale._abbr; + } + + function defineLocale(name, config) { + if (config !== null) { + var locale, + parentConfig = baseConfig; + config.abbr = name; + if (locales[name] != null) { + deprecateSimple( + 'defineLocaleOverride', + 'use moment.updateLocale(localeName, config) to change ' + + 'an existing locale. moment.defineLocale(localeName, ' + + 'config) should only be used for creating a new locale ' + + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.' + ); + parentConfig = locales[name]._config; + } else if (config.parentLocale != null) { + if (locales[config.parentLocale] != null) { + parentConfig = locales[config.parentLocale]._config; + } else { + locale = loadLocale(config.parentLocale); + if (locale != null) { + parentConfig = locale._config; + } else { + if (!localeFamilies[config.parentLocale]) { + localeFamilies[config.parentLocale] = []; + } + localeFamilies[config.parentLocale].push({ + name: name, + config: config, + }); + return null; + } + } + } + locales[name] = new Locale(mergeConfigs(parentConfig, config)); + + if (localeFamilies[name]) { + localeFamilies[name].forEach(function (x) { + defineLocale(x.name, x.config); + }); + } + + // backwards compat for now: also set the locale + // make sure we set the locale AFTER all child locales have been + // created, so we won't end up with the child locale set. + getSetGlobalLocale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + } + + function updateLocale(name, config) { + if (config != null) { + var locale, + tmpLocale, + parentConfig = baseConfig; + + if (locales[name] != null && locales[name].parentLocale != null) { + // Update existing child locale in-place to avoid memory-leaks + locales[name].set(mergeConfigs(locales[name]._config, config)); + } else { + // MERGE + tmpLocale = loadLocale(name); + if (tmpLocale != null) { + parentConfig = tmpLocale._config; + } + config = mergeConfigs(parentConfig, config); + if (tmpLocale == null) { + // updateLocale is called for creating a new locale + // Set abbr so it will have a name (getters return + // undefined otherwise). + config.abbr = name; + } + locale = new Locale(config); + locale.parentLocale = locales[name]; + locales[name] = locale; + } + + // backwards compat for now: also set the locale + getSetGlobalLocale(name); + } else { + // pass null for config to unupdate, useful for tests + if (locales[name] != null) { + if (locales[name].parentLocale != null) { + locales[name] = locales[name].parentLocale; + if (name === getSetGlobalLocale()) { + getSetGlobalLocale(name); + } + } else if (locales[name] != null) { + delete locales[name]; + } + } + } + return locales[name]; + } + + // returns locale data + function getLocale(key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return globalLocale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + } + + function listLocales() { + return keys(locales); + } + + function checkOverflow(m) { + var overflow, + a = m._a; + + if (a && getParsingFlags(m).overflow === -2) { + overflow = + a[MONTH] < 0 || a[MONTH] > 11 + ? MONTH + : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) + ? DATE + : a[HOUR] < 0 || + a[HOUR] > 24 || + (a[HOUR] === 24 && + (a[MINUTE] !== 0 || + a[SECOND] !== 0 || + a[MILLISECOND] !== 0)) + ? HOUR + : a[MINUTE] < 0 || a[MINUTE] > 59 + ? MINUTE + : a[SECOND] < 0 || a[SECOND] > 59 + ? SECOND + : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 + ? MILLISECOND + : -1; + + if ( + getParsingFlags(m)._overflowDayOfYear && + (overflow < YEAR || overflow > DATE) + ) { + overflow = DATE; + } + if (getParsingFlags(m)._overflowWeeks && overflow === -1) { + overflow = WEEK; + } + if (getParsingFlags(m)._overflowWeekday && overflow === -1) { + overflow = WEEKDAY; + } + + getParsingFlags(m).overflow = overflow; + } + + return m; + } + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + var extendedIsoRegex = + /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + basicIsoRegex = + /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + tzRegex = /Z|[+-]\d\d(?::?\d\d)?/, + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], + ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], + ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], + ['GGGG-[W]WW', /\d{4}-W\d\d/, false], + ['YYYY-DDD', /\d{4}-\d{3}/], + ['YYYY-MM', /\d{4}-\d\d/, false], + ['YYYYYYMMDD', /[+-]\d{10}/], + ['YYYYMMDD', /\d{8}/], + ['GGGG[W]WWE', /\d{4}W\d{3}/], + ['GGGG[W]WW', /\d{4}W\d{2}/, false], + ['YYYYDDD', /\d{7}/], + ['YYYYMM', /\d{6}/, false], + ['YYYY', /\d{4}/, false], + ], + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], + ['HH:mm:ss', /\d\d:\d\d:\d\d/], + ['HH:mm', /\d\d:\d\d/], + ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], + ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], + ['HHmmss', /\d\d\d\d\d\d/], + ['HHmm', /\d\d\d\d/], + ['HH', /\d\d/], + ], + aspNetJsonRegex = /^\/?Date\((-?\d+)/i, + // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 + rfc2822 = + /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, + obsOffsets = { + UT: 0, + GMT: 0, + EDT: -4 * 60, + EST: -5 * 60, + CDT: -5 * 60, + CST: -6 * 60, + MDT: -6 * 60, + MST: -7 * 60, + PDT: -7 * 60, + PST: -8 * 60, + }; + + // date from iso format + function configFromISO(config) { + var i, + l, + string = config._i, + match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), + allowTime, + dateFormat, + timeFormat, + tzFormat, + isoDatesLen = isoDates.length, + isoTimesLen = isoTimes.length; + + if (match) { + getParsingFlags(config).iso = true; + for (i = 0, l = isoDatesLen; i < l; i++) { + if (isoDates[i][1].exec(match[1])) { + dateFormat = isoDates[i][0]; + allowTime = isoDates[i][2] !== false; + break; + } + } + if (dateFormat == null) { + config._isValid = false; + return; + } + if (match[3]) { + for (i = 0, l = isoTimesLen; i < l; i++) { + if (isoTimes[i][1].exec(match[3])) { + // match[2] should be 'T' or space + timeFormat = (match[2] || ' ') + isoTimes[i][0]; + break; + } + } + if (timeFormat == null) { + config._isValid = false; + return; + } + } + if (!allowTime && timeFormat != null) { + config._isValid = false; + return; + } + if (match[4]) { + if (tzRegex.exec(match[4])) { + tzFormat = 'Z'; + } else { + config._isValid = false; + return; + } + } + config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); + configFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + function extractFromRFC2822Strings( + yearStr, + monthStr, + dayStr, + hourStr, + minuteStr, + secondStr + ) { + var result = [ + untruncateYear(yearStr), + defaultLocaleMonthsShort.indexOf(monthStr), + parseInt(dayStr, 10), + parseInt(hourStr, 10), + parseInt(minuteStr, 10), + ]; + + if (secondStr) { + result.push(parseInt(secondStr, 10)); + } + + return result; + } + + function untruncateYear(yearStr) { + var year = parseInt(yearStr, 10); + if (year <= 49) { + return 2000 + year; + } else if (year <= 999) { + return 1900 + year; + } + return year; + } + + function preprocessRFC2822(s) { + // Remove comments and folding whitespace and replace multiple-spaces with a single space + return s + .replace(/\([^()]*\)|[\n\t]/g, ' ') + .replace(/(\s\s+)/g, ' ') + .replace(/^\s\s*/, '') + .replace(/\s\s*$/, ''); + } + + function checkWeekday(weekdayStr, parsedInput, config) { + if (weekdayStr) { + // TODO: Replace the vanilla JS Date object with an independent day-of-week check. + var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), + weekdayActual = new Date( + parsedInput[0], + parsedInput[1], + parsedInput[2] + ).getDay(); + if (weekdayProvided !== weekdayActual) { + getParsingFlags(config).weekdayMismatch = true; + config._isValid = false; + return false; + } + } + return true; + } + + function calculateOffset(obsOffset, militaryOffset, numOffset) { + if (obsOffset) { + return obsOffsets[obsOffset]; + } else if (militaryOffset) { + // the only allowed military tz is Z + return 0; + } else { + var hm = parseInt(numOffset, 10), + m = hm % 100, + h = (hm - m) / 100; + return h * 60 + m; + } + } + + // date and time from ref 2822 format + function configFromRFC2822(config) { + var match = rfc2822.exec(preprocessRFC2822(config._i)), + parsedArray; + if (match) { + parsedArray = extractFromRFC2822Strings( + match[4], + match[3], + match[2], + match[5], + match[6], + match[7] + ); + if (!checkWeekday(match[1], parsedArray, config)) { + return; + } + + config._a = parsedArray; + config._tzm = calculateOffset(match[8], match[9], match[10]); + + config._d = createUTCDate.apply(null, config._a); + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + + getParsingFlags(config).rfc2822 = true; + } else { + config._isValid = false; + } + } + + // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict + function configFromString(config) { + var matched = aspNetJsonRegex.exec(config._i); + if (matched !== null) { + config._d = new Date(+matched[1]); + return; + } + + configFromISO(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + configFromRFC2822(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + if (config._strict) { + config._isValid = false; + } else { + // Final attempt, use Input Fallback + hooks.createFromInputFallback(config); + } + } + + hooks.createFromInputFallback = deprecate( + 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + + 'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + // Pick the first defined of two or three arguments. + function defaults(a, b, c) { + if (a != null) { + return a; + } + if (b != null) { + return b; + } + return c; + } + + function currentDateArray(config) { + // hooks is actually the exported moment object + var nowValue = new Date(hooks.now()); + if (config._useUTC) { + return [ + nowValue.getUTCFullYear(), + nowValue.getUTCMonth(), + nowValue.getUTCDate(), + ]; + } + return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function configFromArray(config) { + var i, + date, + input = [], + currentDate, + expectedWeekday, + yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear != null) { + yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); + + if ( + config._dayOfYear > daysInYear(yearToUse) || + config._dayOfYear === 0 + ) { + getParsingFlags(config)._overflowDayOfYear = true; + } + + date = createUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = + config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if ( + config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0 + ) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? createUTCDate : createDate).apply( + null, + input + ); + expectedWeekday = config._useUTC + ? config._d.getUTCDay() + : config._d.getDay(); + + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + + // check for mismatching day of week + if ( + config._w && + typeof config._w.d !== 'undefined' && + config._w.d !== expectedWeekday + ) { + getParsingFlags(config).weekdayMismatch = true; + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = defaults( + w.GG, + config._a[YEAR], + weekOfYear(createLocal(), 1, 4).year + ); + week = defaults(w.W, 1); + weekday = defaults(w.E, 1); + if (weekday < 1 || weekday > 7) { + weekdayOverflow = true; + } + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + curWeek = weekOfYear(createLocal(), dow, doy); + + weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); + + // Default to current week. + week = defaults(w.w, curWeek.week); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < 0 || weekday > 6) { + weekdayOverflow = true; + } + } else if (w.e != null) { + // local weekday -- counting starts from beginning of week + weekday = w.e + dow; + if (w.e < 0 || w.e > 6) { + weekdayOverflow = true; + } + } else { + // default to beginning of week + weekday = dow; + } + } + if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { + getParsingFlags(config)._overflowWeeks = true; + } else if (weekdayOverflow != null) { + getParsingFlags(config)._overflowWeekday = true; + } else { + temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + } + + // constant that refers to the ISO standard + hooks.ISO_8601 = function () {}; + + // constant that refers to the RFC 2822 form + hooks.RFC_2822 = function () {}; + + // date from string and format string + function configFromStringAndFormat(config) { + // TODO: Move this to another part of the creation flow to prevent circular deps + if (config._f === hooks.ISO_8601) { + configFromISO(config); + return; + } + if (config._f === hooks.RFC_2822) { + configFromRFC2822(config); + return; + } + config._a = []; + getParsingFlags(config).empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, + parsedInput, + tokens, + token, + skipped, + stringLength = string.length, + totalParsedInputLength = 0, + era, + tokenLen; + + tokens = + expandFormat(config._f, config._locale).match(formattingTokens) || []; + tokenLen = tokens.length; + for (i = 0; i < tokenLen; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || + [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + getParsingFlags(config).unusedInput.push(skipped); + } + string = string.slice( + string.indexOf(parsedInput) + parsedInput.length + ); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + getParsingFlags(config).empty = false; + } else { + getParsingFlags(config).unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } else if (config._strict && !parsedInput) { + getParsingFlags(config).unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + getParsingFlags(config).charsLeftOver = + stringLength - totalParsedInputLength; + if (string.length > 0) { + getParsingFlags(config).unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if ( + config._a[HOUR] <= 12 && + getParsingFlags(config).bigHour === true && + config._a[HOUR] > 0 + ) { + getParsingFlags(config).bigHour = undefined; + } + + getParsingFlags(config).parsedDateParts = config._a.slice(0); + getParsingFlags(config).meridiem = config._meridiem; + // handle meridiem + config._a[HOUR] = meridiemFixWrap( + config._locale, + config._a[HOUR], + config._meridiem + ); + + // handle era + era = getParsingFlags(config).era; + if (era !== null) { + config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]); + } + + configFromArray(config); + checkOverflow(config); + } + + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // this is not supposed to happen + return hour; + } + } + + // date from string and array of format strings + function configFromStringAndArray(config) { + var tempConfig, + bestMoment, + scoreToBeat, + i, + currentScore, + validFormatFound, + bestFormatIsValid = false, + configfLen = config._f.length; + + if (configfLen === 0) { + getParsingFlags(config).invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < configfLen; i++) { + currentScore = 0; + validFormatFound = false; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._f = config._f[i]; + configFromStringAndFormat(tempConfig); + + if (isValid(tempConfig)) { + validFormatFound = true; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += getParsingFlags(tempConfig).charsLeftOver; + + //or tokens + currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; + + getParsingFlags(tempConfig).score = currentScore; + + if (!bestFormatIsValid) { + if ( + scoreToBeat == null || + currentScore < scoreToBeat || + validFormatFound + ) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + if (validFormatFound) { + bestFormatIsValid = true; + } + } + } else { + if (currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + } + + extend(config, bestMoment || tempConfig); + } + + function configFromObject(config) { + if (config._d) { + return; + } + + var i = normalizeObjectUnits(config._i), + dayOrDate = i.day === undefined ? i.date : i.day; + config._a = map( + [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond], + function (obj) { + return obj && parseInt(obj, 10); + } + ); + + configFromArray(config); + } + + function createFromConfig(config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + function prepareConfig(config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || getLocale(config._l); + + if (input === null || (format === undefined && input === '')) { + return createInvalid({ nullInput: true }); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (isMoment(input)) { + return new Moment(checkOverflow(input)); + } else if (isDate(input)) { + config._d = input; + } else if (isArray(format)) { + configFromStringAndArray(config); + } else if (format) { + configFromStringAndFormat(config); + } else { + configFromInput(config); + } + + if (!isValid(config)) { + config._d = null; + } + + return config; + } + + function configFromInput(config) { + var input = config._i; + if (isUndefined(input)) { + config._d = new Date(hooks.now()); + } else if (isDate(input)) { + config._d = new Date(input.valueOf()); + } else if (typeof input === 'string') { + configFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + configFromArray(config); + } else if (isObject(input)) { + configFromObject(config); + } else if (isNumber(input)) { + // from milliseconds + config._d = new Date(input); + } else { + hooks.createFromInputFallback(config); + } + } + + function createLocalOrUTC(input, format, locale, strict, isUTC) { + var c = {}; + + if (format === true || format === false) { + strict = format; + format = undefined; + } + + if (locale === true || locale === false) { + strict = locale; + locale = undefined; + } + + if ( + (isObject(input) && isObjectEmpty(input)) || + (isArray(input) && input.length === 0) + ) { + input = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c._isAMomentObject = true; + c._useUTC = c._isUTC = isUTC; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + + return createFromConfig(c); + } + + function createLocal(input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, false); + } + + var prototypeMin = deprecate( + 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other < this ? this : other; + } else { + return createInvalid(); + } + } + ), + prototypeMax = deprecate( + 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other > this ? this : other; + } else { + return createInvalid(); + } + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return createLocal(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (!moments[i].isValid() || moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + // TODO: Use [].sort instead? + function min() { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + } + + function max() { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + } + + var now = function () { + return Date.now ? Date.now() : +new Date(); + }; + + var ordering = [ + 'year', + 'quarter', + 'month', + 'week', + 'day', + 'hour', + 'minute', + 'second', + 'millisecond', + ]; + + function isDurationValid(m) { + var key, + unitHasDecimal = false, + i, + orderLen = ordering.length; + for (key in m) { + if ( + hasOwnProp(m, key) && + !( + indexOf.call(ordering, key) !== -1 && + (m[key] == null || !isNaN(m[key])) + ) + ) { + return false; + } + } + + for (i = 0; i < orderLen; ++i) { + if (m[ordering[i]]) { + if (unitHasDecimal) { + return false; // only allow non-integers for smallest unit + } + if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { + unitHasDecimal = true; + } + } + } + + return true; + } + + function isValid$1() { + return this._isValid; + } + + function createInvalid$1() { + return createDuration(NaN); + } + + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || normalizedInput.isoWeek || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + this._isValid = isDurationValid(normalizedInput); + + // representation for dateAddRemove + this._milliseconds = + +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + weeks * 7; + // It is impossible to translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + quarters * 3 + years * 12; + + this._data = {}; + + this._locale = getLocale(); + + this._bubble(); + } + + function isDuration(obj) { + return obj instanceof Duration; + } + + function absRound(number) { + if (number < 0) { + return Math.round(-1 * number) * -1; + } else { + return Math.round(number); + } + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ( + (dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i])) + ) { + diffs++; + } + } + return diffs + lengthDiff; + } + + // FORMATTING + + function offset(token, separator) { + addFormatToken(token, 0, 0, function () { + var offset = this.utcOffset(), + sign = '+'; + if (offset < 0) { + offset = -offset; + sign = '-'; + } + return ( + sign + + zeroFill(~~(offset / 60), 2) + + separator + + zeroFill(~~offset % 60, 2) + ); + }); + } + + offset('Z', ':'); + offset('ZZ', ''); + + // PARSING + + addRegexToken('Z', matchShortOffset); + addRegexToken('ZZ', matchShortOffset); + addParseToken(['Z', 'ZZ'], function (input, array, config) { + config._useUTC = true; + config._tzm = offsetFromString(matchShortOffset, input); + }); + + // HELPERS + + // timezone chunker + // '+10:00' > ['10', '00'] + // '-1530' > ['-15', '30'] + var chunkOffset = /([\+\-]|\d\d)/gi; + + function offsetFromString(matcher, string) { + var matches = (string || '').match(matcher), + chunk, + parts, + minutes; + + if (matches === null) { + return null; + } + + chunk = matches[matches.length - 1] || []; + parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function cloneWithOffset(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = + (isMoment(input) || isDate(input) + ? input.valueOf() + : createLocal(input).valueOf()) - res.valueOf(); + // Use low-level api, because this fn is low-level api. + res._d.setTime(res._d.valueOf() + diff); + hooks.updateOffset(res, false); + return res; + } else { + return createLocal(input).local(); + } + } + + function getDateOffset(m) { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(m._d.getTimezoneOffset()); + } + + // HOOKS + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + hooks.updateOffset = function () {}; + + // MOMENTS + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + function getSetOffset(input, keepLocalTime, keepMinutes) { + var offset = this._offset || 0, + localAdjust; + if (!this.isValid()) { + return input != null ? this : NaN; + } + if (input != null) { + if (typeof input === 'string') { + input = offsetFromString(matchShortOffset, input); + if (input === null) { + return this; + } + } else if (Math.abs(input) < 16 && !keepMinutes) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = getDateOffset(this); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addSubtract( + this, + createDuration(input - offset, 'm'), + 1, + false + ); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + hooks.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : getDateOffset(this); + } + } + + function getSetZone(input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + + function setOffsetToUTC(keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + } + + function setOffsetToLocal(keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(getDateOffset(this), 'm'); + } + } + return this; + } + + function setOffsetToParsedOffset() { + if (this._tzm != null) { + this.utcOffset(this._tzm, false, true); + } else if (typeof this._i === 'string') { + var tZone = offsetFromString(matchOffset, this._i); + if (tZone != null) { + this.utcOffset(tZone); + } else { + this.utcOffset(0, true); + } + } + return this; + } + + function hasAlignedHourOffset(input) { + if (!this.isValid()) { + return false; + } + input = input ? createLocal(input).utcOffset() : 0; + + return (this.utcOffset() - input) % 60 === 0; + } + + function isDaylightSavingTime() { + return ( + this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset() + ); + } + + function isDaylightSavingTimeShifted() { + if (!isUndefined(this._isDSTShifted)) { + return this._isDSTShifted; + } + + var c = {}, + other; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + other = c._isUTC ? createUTC(c._a) : createLocal(c._a); + this._isDSTShifted = + this.isValid() && compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; + } + + function isLocal() { + return this.isValid() ? !this._isUTC : false; + } + + function isUtcOffset() { + return this.isValid() ? this._isUTC : false; + } + + function isUtc() { + return this.isValid() ? this._isUTC && this._offset === 0 : false; + } + + // ASP.NET json date format regex + var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + // and further modified to allow for strings containing both week and day + isoRegex = + /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; + + function createDuration(input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + diffRes; + + if (isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months, + }; + } else if (isNumber(input) || !isNaN(+input)) { + duration = {}; + if (key) { + duration[key] = +input; + } else { + duration.milliseconds = +input; + } + } else if ((match = aspNetRegex.exec(input))) { + sign = match[1] === '-' ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match + }; + } else if ((match = isoRegex.exec(input))) { + sign = match[1] === '-' ? -1 : 1; + duration = { + y: parseIso(match[2], sign), + M: parseIso(match[3], sign), + w: parseIso(match[4], sign), + d: parseIso(match[5], sign), + h: parseIso(match[6], sign), + m: parseIso(match[7], sign), + s: parseIso(match[8], sign), + }; + } else if (duration == null) { + // checks for null or undefined + duration = {}; + } else if ( + typeof duration === 'object' && + ('from' in duration || 'to' in duration) + ) { + diffRes = momentsDifference( + createLocal(duration.from), + createLocal(duration.to) + ); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + if (isDuration(input) && hasOwnProp(input, '_isValid')) { + ret._isValid = input._isValid; + } + + return ret; + } + + createDuration.fn = Duration.prototype; + createDuration.invalid = createInvalid$1; + + function parseIso(inp, sign) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + } + + function positiveMomentsDifference(base, other) { + var res = {}; + + res.months = + other.month() - base.month() + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +base.clone().add(res.months, 'M'); + + return res; + } + + function momentsDifference(base, other) { + var res; + if (!(base.isValid() && other.isValid())) { + return { milliseconds: 0, months: 0 }; + } + + other = cloneWithOffset(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple( + name, + 'moment().' + + name + + '(period, number) is deprecated. Please use moment().' + + name + + '(number, period). ' + + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.' + ); + tmp = val; + val = period; + period = tmp; + } + + dur = createDuration(val, period); + addSubtract(this, dur, direction); + return this; + }; + } + + function addSubtract(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = absRound(duration._days), + months = absRound(duration._months); + + if (!mom.isValid()) { + // No op + return; + } + + updateOffset = updateOffset == null ? true : updateOffset; + + if (months) { + setMonth(mom, get(mom, 'Month') + months * isAdding); + } + if (days) { + set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); + } + if (milliseconds) { + mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); + } + if (updateOffset) { + hooks.updateOffset(mom, days || months); + } + } + + var add = createAdder(1, 'add'), + subtract = createAdder(-1, 'subtract'); + + function isString(input) { + return typeof input === 'string' || input instanceof String; + } + + // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined + function isMomentInput(input) { + return ( + isMoment(input) || + isDate(input) || + isString(input) || + isNumber(input) || + isNumberOrStringArray(input) || + isMomentInputObject(input) || + input === null || + input === undefined + ); + } + + function isMomentInputObject(input) { + var objectTest = isObject(input) && !isObjectEmpty(input), + propertyTest = false, + properties = [ + 'years', + 'year', + 'y', + 'months', + 'month', + 'M', + 'days', + 'day', + 'd', + 'dates', + 'date', + 'D', + 'hours', + 'hour', + 'h', + 'minutes', + 'minute', + 'm', + 'seconds', + 'second', + 's', + 'milliseconds', + 'millisecond', + 'ms', + ], + i, + property, + propertyLen = properties.length; + + for (i = 0; i < propertyLen; i += 1) { + property = properties[i]; + propertyTest = propertyTest || hasOwnProp(input, property); + } + + return objectTest && propertyTest; + } + + function isNumberOrStringArray(input) { + var arrayTest = isArray(input), + dataTypeTest = false; + if (arrayTest) { + dataTypeTest = + input.filter(function (item) { + return !isNumber(item) && isString(input); + }).length === 0; + } + return arrayTest && dataTypeTest; + } + + function isCalendarSpec(input) { + var objectTest = isObject(input) && !isObjectEmpty(input), + propertyTest = false, + properties = [ + 'sameDay', + 'nextDay', + 'lastDay', + 'nextWeek', + 'lastWeek', + 'sameElse', + ], + i, + property; + + for (i = 0; i < properties.length; i += 1) { + property = properties[i]; + propertyTest = propertyTest || hasOwnProp(input, property); + } + + return objectTest && propertyTest; + } + + function getCalendarFormat(myMoment, now) { + var diff = myMoment.diff(now, 'days', true); + return diff < -6 + ? 'sameElse' + : diff < -1 + ? 'lastWeek' + : diff < 0 + ? 'lastDay' + : diff < 1 + ? 'sameDay' + : diff < 2 + ? 'nextDay' + : diff < 7 + ? 'nextWeek' + : 'sameElse'; + } + + function calendar$1(time, formats) { + // Support for single parameter, formats only overload to the calendar function + if (arguments.length === 1) { + if (!arguments[0]) { + time = undefined; + formats = undefined; + } else if (isMomentInput(arguments[0])) { + time = arguments[0]; + formats = undefined; + } else if (isCalendarSpec(arguments[0])) { + formats = arguments[0]; + time = undefined; + } + } + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're local/utc/offset or not. + var now = time || createLocal(), + sod = cloneWithOffset(now, this).startOf('day'), + format = hooks.calendarFormat(this, sod) || 'sameElse', + output = + formats && + (isFunction(formats[format]) + ? formats[format].call(this, now) + : formats[format]); + + return this.format( + output || this.localeData().calendar(format, this, createLocal(now)) + ); + } + + function clone() { + return new Moment(this); + } + + function isAfter(input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() > localInput.valueOf(); + } else { + return localInput.valueOf() < this.clone().startOf(units).valueOf(); + } + } + + function isBefore(input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() < localInput.valueOf(); + } else { + return this.clone().endOf(units).valueOf() < localInput.valueOf(); + } + } + + function isBetween(from, to, units, inclusivity) { + var localFrom = isMoment(from) ? from : createLocal(from), + localTo = isMoment(to) ? to : createLocal(to); + if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) { + return false; + } + inclusivity = inclusivity || '()'; + return ( + (inclusivity[0] === '(' + ? this.isAfter(localFrom, units) + : !this.isBefore(localFrom, units)) && + (inclusivity[1] === ')' + ? this.isBefore(localTo, units) + : !this.isAfter(localTo, units)) + ); + } + + function isSame(input, units) { + var localInput = isMoment(input) ? input : createLocal(input), + inputMs; + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units) || 'millisecond'; + if (units === 'millisecond') { + return this.valueOf() === localInput.valueOf(); + } else { + inputMs = localInput.valueOf(); + return ( + this.clone().startOf(units).valueOf() <= inputMs && + inputMs <= this.clone().endOf(units).valueOf() + ); + } + } + + function isSameOrAfter(input, units) { + return this.isSame(input, units) || this.isAfter(input, units); + } + + function isSameOrBefore(input, units) { + return this.isSame(input, units) || this.isBefore(input, units); + } + + function diff(input, units, asFloat) { + var that, zoneDelta, output; + + if (!this.isValid()) { + return NaN; + } + + that = cloneWithOffset(input, this); + + if (!that.isValid()) { + return NaN; + } + + zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; + + units = normalizeUnits(units); + + switch (units) { + case 'year': + output = monthDiff(this, that) / 12; + break; + case 'month': + output = monthDiff(this, that); + break; + case 'quarter': + output = monthDiff(this, that) / 3; + break; + case 'second': + output = (this - that) / 1e3; + break; // 1000 + case 'minute': + output = (this - that) / 6e4; + break; // 1000 * 60 + case 'hour': + output = (this - that) / 36e5; + break; // 1000 * 60 * 60 + case 'day': + output = (this - that - zoneDelta) / 864e5; + break; // 1000 * 60 * 60 * 24, negate dst + case 'week': + output = (this - that - zoneDelta) / 6048e5; + break; // 1000 * 60 * 60 * 24 * 7, negate dst + default: + output = this - that; + } + + return asFloat ? output : absFloor(output); + } + + function monthDiff(a, b) { + if (a.date() < b.date()) { + // end-of-month calculations work correct when the start month has more + // days than the end month. + return -monthDiff(b, a); + } + // difference in months + var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, + adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + //check for negative zero, return zero if negative zero + return -(wholeMonthDiff + adjust) || 0; + } + + hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; + hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; + + function toString() { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + } + + function toISOString(keepOffset) { + if (!this.isValid()) { + return null; + } + var utc = keepOffset !== true, + m = utc ? this.clone().utc() : this; + if (m.year() < 0 || m.year() > 9999) { + return formatMoment( + m, + utc + ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' + : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ' + ); + } + if (isFunction(Date.prototype.toISOString)) { + // native implementation is ~50x faster, use it when we can + if (utc) { + return this.toDate().toISOString(); + } else { + return new Date(this.valueOf() + this.utcOffset() * 60 * 1000) + .toISOString() + .replace('Z', formatMoment(m, 'Z')); + } + } + return formatMoment( + m, + utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ' + ); + } + + /** + * Return a human readable representation of a moment that can + * also be evaluated to get a new moment which is the same + * + * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects + */ + function inspect() { + if (!this.isValid()) { + return 'moment.invalid(/* ' + this._i + ' */)'; + } + var func = 'moment', + zone = '', + prefix, + year, + datetime, + suffix; + if (!this.isLocal()) { + func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; + zone = 'Z'; + } + prefix = '[' + func + '("]'; + year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY'; + datetime = '-MM-DD[T]HH:mm:ss.SSS'; + suffix = zone + '[")]'; + + return this.format(prefix + year + datetime + suffix); + } + + function format(inputString) { + if (!inputString) { + inputString = this.isUtc() + ? hooks.defaultFormatUtc + : hooks.defaultFormat; + } + var output = formatMoment(this, inputString); + return this.localeData().postformat(output); + } + + function from(time, withoutSuffix) { + if ( + this.isValid() && + ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) + ) { + return createDuration({ to: this, from: time }) + .locale(this.locale()) + .humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function fromNow(withoutSuffix) { + return this.from(createLocal(), withoutSuffix); + } + + function to(time, withoutSuffix) { + if ( + this.isValid() && + ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) + ) { + return createDuration({ from: this, to: time }) + .locale(this.locale()) + .humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } + } + + function toNow(withoutSuffix) { + return this.to(createLocal(), withoutSuffix); + } + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + function locale(key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = getLocale(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + } + + var lang = deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ); + + function localeData() { + return this._locale; + } + + var MS_PER_SECOND = 1000, + MS_PER_MINUTE = 60 * MS_PER_SECOND, + MS_PER_HOUR = 60 * MS_PER_MINUTE, + MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; + + // actual modulo - handles negative numbers (for dates before 1970): + function mod$1(dividend, divisor) { + return ((dividend % divisor) + divisor) % divisor; + } + + function localStartOfDate(y, m, d) { + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + return new Date(y + 400, m, d) - MS_PER_400_YEARS; + } else { + return new Date(y, m, d).valueOf(); + } + } + + function utcStartOfDate(y, m, d) { + // Date.UTC remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0) { + // preserve leap years using a full 400 year cycle, then reset + return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS; + } else { + return Date.UTC(y, m, d); + } + } + + function startOf(units) { + var time, startOfDate; + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond' || !this.isValid()) { + return this; + } + + startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; + + switch (units) { + case 'year': + time = startOfDate(this.year(), 0, 1); + break; + case 'quarter': + time = startOfDate( + this.year(), + this.month() - (this.month() % 3), + 1 + ); + break; + case 'month': + time = startOfDate(this.year(), this.month(), 1); + break; + case 'week': + time = startOfDate( + this.year(), + this.month(), + this.date() - this.weekday() + ); + break; + case 'isoWeek': + time = startOfDate( + this.year(), + this.month(), + this.date() - (this.isoWeekday() - 1) + ); + break; + case 'day': + case 'date': + time = startOfDate(this.year(), this.month(), this.date()); + break; + case 'hour': + time = this._d.valueOf(); + time -= mod$1( + time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), + MS_PER_HOUR + ); + break; + case 'minute': + time = this._d.valueOf(); + time -= mod$1(time, MS_PER_MINUTE); + break; + case 'second': + time = this._d.valueOf(); + time -= mod$1(time, MS_PER_SECOND); + break; + } + + this._d.setTime(time); + hooks.updateOffset(this, true); + return this; + } + + function endOf(units) { + var time, startOfDate; + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond' || !this.isValid()) { + return this; + } + + startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; + + switch (units) { + case 'year': + time = startOfDate(this.year() + 1, 0, 1) - 1; + break; + case 'quarter': + time = + startOfDate( + this.year(), + this.month() - (this.month() % 3) + 3, + 1 + ) - 1; + break; + case 'month': + time = startOfDate(this.year(), this.month() + 1, 1) - 1; + break; + case 'week': + time = + startOfDate( + this.year(), + this.month(), + this.date() - this.weekday() + 7 + ) - 1; + break; + case 'isoWeek': + time = + startOfDate( + this.year(), + this.month(), + this.date() - (this.isoWeekday() - 1) + 7 + ) - 1; + break; + case 'day': + case 'date': + time = startOfDate(this.year(), this.month(), this.date() + 1) - 1; + break; + case 'hour': + time = this._d.valueOf(); + time += + MS_PER_HOUR - + mod$1( + time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), + MS_PER_HOUR + ) - + 1; + break; + case 'minute': + time = this._d.valueOf(); + time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1; + break; + case 'second': + time = this._d.valueOf(); + time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1; + break; + } + + this._d.setTime(time); + hooks.updateOffset(this, true); + return this; + } + + function valueOf() { + return this._d.valueOf() - (this._offset || 0) * 60000; + } + + function unix() { + return Math.floor(this.valueOf() / 1000); + } + + function toDate() { + return new Date(this.valueOf()); + } + + function toArray() { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hour(), + m.minute(), + m.second(), + m.millisecond(), + ]; + } + + function toObject() { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds(), + }; + } + + function toJSON() { + // new Date(NaN).toJSON() === null + return this.isValid() ? this.toISOString() : null; + } + + function isValid$2() { + return isValid(this); + } + + function parsingFlags() { + return extend({}, getParsingFlags(this)); + } + + function invalidAt() { + return getParsingFlags(this).overflow; + } + + function creationData() { + return { + input: this._i, + format: this._f, + locale: this._locale, + isUTC: this._isUTC, + strict: this._strict, + }; + } + + addFormatToken('N', 0, 0, 'eraAbbr'); + addFormatToken('NN', 0, 0, 'eraAbbr'); + addFormatToken('NNN', 0, 0, 'eraAbbr'); + addFormatToken('NNNN', 0, 0, 'eraName'); + addFormatToken('NNNNN', 0, 0, 'eraNarrow'); + + addFormatToken('y', ['y', 1], 'yo', 'eraYear'); + addFormatToken('y', ['yy', 2], 0, 'eraYear'); + addFormatToken('y', ['yyy', 3], 0, 'eraYear'); + addFormatToken('y', ['yyyy', 4], 0, 'eraYear'); + + addRegexToken('N', matchEraAbbr); + addRegexToken('NN', matchEraAbbr); + addRegexToken('NNN', matchEraAbbr); + addRegexToken('NNNN', matchEraName); + addRegexToken('NNNNN', matchEraNarrow); + + addParseToken( + ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], + function (input, array, config, token) { + var era = config._locale.erasParse(input, token, config._strict); + if (era) { + getParsingFlags(config).era = era; + } else { + getParsingFlags(config).invalidEra = input; + } + } + ); + + addRegexToken('y', matchUnsigned); + addRegexToken('yy', matchUnsigned); + addRegexToken('yyy', matchUnsigned); + addRegexToken('yyyy', matchUnsigned); + addRegexToken('yo', matchEraYearOrdinal); + + addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR); + addParseToken(['yo'], function (input, array, config, token) { + var match; + if (config._locale._eraYearOrdinalRegex) { + match = input.match(config._locale._eraYearOrdinalRegex); + } + + if (config._locale.eraYearOrdinalParse) { + array[YEAR] = config._locale.eraYearOrdinalParse(input, match); + } else { + array[YEAR] = parseInt(input, 10); + } + }); + + function localeEras(m, format) { + var i, + l, + date, + eras = this._eras || getLocale('en')._eras; + for (i = 0, l = eras.length; i < l; ++i) { + switch (typeof eras[i].since) { + case 'string': + // truncate time + date = hooks(eras[i].since).startOf('day'); + eras[i].since = date.valueOf(); + break; + } + + switch (typeof eras[i].until) { + case 'undefined': + eras[i].until = +Infinity; + break; + case 'string': + // truncate time + date = hooks(eras[i].until).startOf('day').valueOf(); + eras[i].until = date.valueOf(); + break; + } + } + return eras; + } + + function localeErasParse(eraName, format, strict) { + var i, + l, + eras = this.eras(), + name, + abbr, + narrow; + eraName = eraName.toUpperCase(); + + for (i = 0, l = eras.length; i < l; ++i) { + name = eras[i].name.toUpperCase(); + abbr = eras[i].abbr.toUpperCase(); + narrow = eras[i].narrow.toUpperCase(); + + if (strict) { + switch (format) { + case 'N': + case 'NN': + case 'NNN': + if (abbr === eraName) { + return eras[i]; + } + break; + + case 'NNNN': + if (name === eraName) { + return eras[i]; + } + break; + + case 'NNNNN': + if (narrow === eraName) { + return eras[i]; + } + break; + } + } else if ([name, abbr, narrow].indexOf(eraName) >= 0) { + return eras[i]; + } + } + } + + function localeErasConvertYear(era, year) { + var dir = era.since <= era.until ? +1 : -1; + if (year === undefined) { + return hooks(era.since).year(); + } else { + return hooks(era.since).year() + (year - era.offset) * dir; + } + } + + function getEraName() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].name; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].name; + } + } + + return ''; + } + + function getEraNarrow() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].narrow; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].narrow; + } + } + + return ''; + } + + function getEraAbbr() { + var i, + l, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + // truncate time + val = this.clone().startOf('day').valueOf(); + + if (eras[i].since <= val && val <= eras[i].until) { + return eras[i].abbr; + } + if (eras[i].until <= val && val <= eras[i].since) { + return eras[i].abbr; + } + } + + return ''; + } + + function getEraYear() { + var i, + l, + dir, + val, + eras = this.localeData().eras(); + for (i = 0, l = eras.length; i < l; ++i) { + dir = eras[i].since <= eras[i].until ? +1 : -1; + + // truncate time + val = this.clone().startOf('day').valueOf(); + + if ( + (eras[i].since <= val && val <= eras[i].until) || + (eras[i].until <= val && val <= eras[i].since) + ) { + return ( + (this.year() - hooks(eras[i].since).year()) * dir + + eras[i].offset + ); + } + } + + return this.year(); + } + + function erasNameRegex(isStrict) { + if (!hasOwnProp(this, '_erasNameRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasNameRegex : this._erasRegex; + } + + function erasAbbrRegex(isStrict) { + if (!hasOwnProp(this, '_erasAbbrRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasAbbrRegex : this._erasRegex; + } + + function erasNarrowRegex(isStrict) { + if (!hasOwnProp(this, '_erasNarrowRegex')) { + computeErasParse.call(this); + } + return isStrict ? this._erasNarrowRegex : this._erasRegex; + } + + function matchEraAbbr(isStrict, locale) { + return locale.erasAbbrRegex(isStrict); + } + + function matchEraName(isStrict, locale) { + return locale.erasNameRegex(isStrict); + } + + function matchEraNarrow(isStrict, locale) { + return locale.erasNarrowRegex(isStrict); + } + + function matchEraYearOrdinal(isStrict, locale) { + return locale._eraYearOrdinalRegex || matchUnsigned; + } + + function computeErasParse() { + var abbrPieces = [], + namePieces = [], + narrowPieces = [], + mixedPieces = [], + i, + l, + eras = this.eras(); + + for (i = 0, l = eras.length; i < l; ++i) { + namePieces.push(regexEscape(eras[i].name)); + abbrPieces.push(regexEscape(eras[i].abbr)); + narrowPieces.push(regexEscape(eras[i].narrow)); + + mixedPieces.push(regexEscape(eras[i].name)); + mixedPieces.push(regexEscape(eras[i].abbr)); + mixedPieces.push(regexEscape(eras[i].narrow)); + } + + this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i'); + this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i'); + this._erasNarrowRegex = new RegExp( + '^(' + narrowPieces.join('|') + ')', + 'i' + ); + } + + // FORMATTING + + addFormatToken(0, ['gg', 2], 0, function () { + return this.weekYear() % 100; + }); + + addFormatToken(0, ['GG', 2], 0, function () { + return this.isoWeekYear() % 100; + }); + + function addWeekYearFormatToken(token, getter) { + addFormatToken(0, [token, token.length], 0, getter); + } + + addWeekYearFormatToken('gggg', 'weekYear'); + addWeekYearFormatToken('ggggg', 'weekYear'); + addWeekYearFormatToken('GGGG', 'isoWeekYear'); + addWeekYearFormatToken('GGGGG', 'isoWeekYear'); + + // ALIASES + + addUnitAlias('weekYear', 'gg'); + addUnitAlias('isoWeekYear', 'GG'); + + // PRIORITY + + addUnitPriority('weekYear', 1); + addUnitPriority('isoWeekYear', 1); + + // PARSING + + addRegexToken('G', matchSigned); + addRegexToken('g', matchSigned); + addRegexToken('GG', match1to2, match2); + addRegexToken('gg', match1to2, match2); + addRegexToken('GGGG', match1to4, match4); + addRegexToken('gggg', match1to4, match4); + addRegexToken('GGGGG', match1to6, match6); + addRegexToken('ggggg', match1to6, match6); + + addWeekParseToken( + ['gggg', 'ggggg', 'GGGG', 'GGGGG'], + function (input, week, config, token) { + week[token.substr(0, 2)] = toInt(input); + } + ); + + addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { + week[token] = hooks.parseTwoDigitYear(input); + }); + + // MOMENTS + + function getSetWeekYear(input) { + return getSetWeekYearHelper.call( + this, + input, + this.week(), + this.weekday(), + this.localeData()._week.dow, + this.localeData()._week.doy + ); + } + + function getSetISOWeekYear(input) { + return getSetWeekYearHelper.call( + this, + input, + this.isoWeek(), + this.isoWeekday(), + 1, + 4 + ); + } + + function getISOWeeksInYear() { + return weeksInYear(this.year(), 1, 4); + } + + function getISOWeeksInISOWeekYear() { + return weeksInYear(this.isoWeekYear(), 1, 4); + } + + function getWeeksInYear() { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + } + + function getWeeksInWeekYear() { + var weekInfo = this.localeData()._week; + return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy); + } + + function getSetWeekYearHelper(input, week, weekday, dow, doy) { + var weeksTarget; + if (input == null) { + return weekOfYear(this, dow, doy).year; + } else { + weeksTarget = weeksInYear(input, dow, doy); + if (week > weeksTarget) { + week = weeksTarget; + } + return setWeekAll.call(this, input, week, weekday, dow, doy); + } + } + + function setWeekAll(weekYear, week, weekday, dow, doy) { + var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), + date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); + + this.year(date.getUTCFullYear()); + this.month(date.getUTCMonth()); + this.date(date.getUTCDate()); + return this; + } + + // FORMATTING + + addFormatToken('Q', 0, 'Qo', 'quarter'); + + // ALIASES + + addUnitAlias('quarter', 'Q'); + + // PRIORITY + + addUnitPriority('quarter', 7); + + // PARSING + + addRegexToken('Q', match1); + addParseToken('Q', function (input, array) { + array[MONTH] = (toInt(input) - 1) * 3; + }); + + // MOMENTS + + function getSetQuarter(input) { + return input == null + ? Math.ceil((this.month() + 1) / 3) + : this.month((input - 1) * 3 + (this.month() % 3)); + } + + // FORMATTING + + addFormatToken('D', ['DD', 2], 'Do', 'date'); + + // ALIASES + + addUnitAlias('date', 'D'); + + // PRIORITY + addUnitPriority('date', 9); + + // PARSING + + addRegexToken('D', match1to2); + addRegexToken('DD', match1to2, match2); + addRegexToken('Do', function (isStrict, locale) { + // TODO: Remove "ordinalParse" fallback in next major release. + return isStrict + ? locale._dayOfMonthOrdinalParse || locale._ordinalParse + : locale._dayOfMonthOrdinalParseLenient; + }); + + addParseToken(['D', 'DD'], DATE); + addParseToken('Do', function (input, array) { + array[DATE] = toInt(input.match(match1to2)[0]); + }); + + // MOMENTS + + var getSetDayOfMonth = makeGetSet('Date', true); + + // FORMATTING + + addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); + + // ALIASES + + addUnitAlias('dayOfYear', 'DDD'); + + // PRIORITY + addUnitPriority('dayOfYear', 4); + + // PARSING + + addRegexToken('DDD', match1to3); + addRegexToken('DDDD', match3); + addParseToken(['DDD', 'DDDD'], function (input, array, config) { + config._dayOfYear = toInt(input); + }); + + // HELPERS + + // MOMENTS + + function getSetDayOfYear(input) { + var dayOfYear = + Math.round( + (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5 + ) + 1; + return input == null ? dayOfYear : this.add(input - dayOfYear, 'd'); + } + + // FORMATTING + + addFormatToken('m', ['mm', 2], 0, 'minute'); + + // ALIASES + + addUnitAlias('minute', 'm'); + + // PRIORITY + + addUnitPriority('minute', 14); + + // PARSING + + addRegexToken('m', match1to2); + addRegexToken('mm', match1to2, match2); + addParseToken(['m', 'mm'], MINUTE); + + // MOMENTS + + var getSetMinute = makeGetSet('Minutes', false); + + // FORMATTING + + addFormatToken('s', ['ss', 2], 0, 'second'); + + // ALIASES + + addUnitAlias('second', 's'); + + // PRIORITY + + addUnitPriority('second', 15); + + // PARSING + + addRegexToken('s', match1to2); + addRegexToken('ss', match1to2, match2); + addParseToken(['s', 'ss'], SECOND); + + // MOMENTS + + var getSetSecond = makeGetSet('Seconds', false); + + // FORMATTING + + addFormatToken('S', 0, 0, function () { + return ~~(this.millisecond() / 100); + }); + + addFormatToken(0, ['SS', 2], 0, function () { + return ~~(this.millisecond() / 10); + }); + + addFormatToken(0, ['SSS', 3], 0, 'millisecond'); + addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; + }); + addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; + }); + addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; + }); + addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; + }); + addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; + }); + addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; + }); + + // ALIASES + + addUnitAlias('millisecond', 'ms'); + + // PRIORITY + + addUnitPriority('millisecond', 16); + + // PARSING + + addRegexToken('S', match1to3, match1); + addRegexToken('SS', match1to3, match2); + addRegexToken('SSS', match1to3, match3); + + var token, getSetMillisecond; + for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); + } + + function parseMs(input, array) { + array[MILLISECOND] = toInt(('0.' + input) * 1000); + } + + for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); + } + + getSetMillisecond = makeGetSet('Milliseconds', false); + + // FORMATTING + + addFormatToken('z', 0, 0, 'zoneAbbr'); + addFormatToken('zz', 0, 0, 'zoneName'); + + // MOMENTS + + function getZoneAbbr() { + return this._isUTC ? 'UTC' : ''; + } + + function getZoneName() { + return this._isUTC ? 'Coordinated Universal Time' : ''; + } + + var proto = Moment.prototype; + + proto.add = add; + proto.calendar = calendar$1; + proto.clone = clone; + proto.diff = diff; + proto.endOf = endOf; + proto.format = format; + proto.from = from; + proto.fromNow = fromNow; + proto.to = to; + proto.toNow = toNow; + proto.get = stringGet; + proto.invalidAt = invalidAt; + proto.isAfter = isAfter; + proto.isBefore = isBefore; + proto.isBetween = isBetween; + proto.isSame = isSame; + proto.isSameOrAfter = isSameOrAfter; + proto.isSameOrBefore = isSameOrBefore; + proto.isValid = isValid$2; + proto.lang = lang; + proto.locale = locale; + proto.localeData = localeData; + proto.max = prototypeMax; + proto.min = prototypeMin; + proto.parsingFlags = parsingFlags; + proto.set = stringSet; + proto.startOf = startOf; + proto.subtract = subtract; + proto.toArray = toArray; + proto.toObject = toObject; + proto.toDate = toDate; + proto.toISOString = toISOString; + proto.inspect = inspect; + if (typeof Symbol !== 'undefined' && Symbol.for != null) { + proto[Symbol.for('nodejs.util.inspect.custom')] = function () { + return 'Moment<' + this.format() + '>'; + }; + } + proto.toJSON = toJSON; + proto.toString = toString; + proto.unix = unix; + proto.valueOf = valueOf; + proto.creationData = creationData; + proto.eraName = getEraName; + proto.eraNarrow = getEraNarrow; + proto.eraAbbr = getEraAbbr; + proto.eraYear = getEraYear; + proto.year = getSetYear; + proto.isLeapYear = getIsLeapYear; + proto.weekYear = getSetWeekYear; + proto.isoWeekYear = getSetISOWeekYear; + proto.quarter = proto.quarters = getSetQuarter; + proto.month = getSetMonth; + proto.daysInMonth = getDaysInMonth; + proto.week = proto.weeks = getSetWeek; + proto.isoWeek = proto.isoWeeks = getSetISOWeek; + proto.weeksInYear = getWeeksInYear; + proto.weeksInWeekYear = getWeeksInWeekYear; + proto.isoWeeksInYear = getISOWeeksInYear; + proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear; + proto.date = getSetDayOfMonth; + proto.day = proto.days = getSetDayOfWeek; + proto.weekday = getSetLocaleDayOfWeek; + proto.isoWeekday = getSetISODayOfWeek; + proto.dayOfYear = getSetDayOfYear; + proto.hour = proto.hours = getSetHour; + proto.minute = proto.minutes = getSetMinute; + proto.second = proto.seconds = getSetSecond; + proto.millisecond = proto.milliseconds = getSetMillisecond; + proto.utcOffset = getSetOffset; + proto.utc = setOffsetToUTC; + proto.local = setOffsetToLocal; + proto.parseZone = setOffsetToParsedOffset; + proto.hasAlignedHourOffset = hasAlignedHourOffset; + proto.isDST = isDaylightSavingTime; + proto.isLocal = isLocal; + proto.isUtcOffset = isUtcOffset; + proto.isUtc = isUtc; + proto.isUTC = isUtc; + proto.zoneAbbr = getZoneAbbr; + proto.zoneName = getZoneName; + proto.dates = deprecate( + 'dates accessor is deprecated. Use date instead.', + getSetDayOfMonth + ); + proto.months = deprecate( + 'months accessor is deprecated. Use month instead', + getSetMonth + ); + proto.years = deprecate( + 'years accessor is deprecated. Use year instead', + getSetYear + ); + proto.zone = deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', + getSetZone + ); + proto.isDSTShifted = deprecate( + 'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', + isDaylightSavingTimeShifted + ); + + function createUnix(input) { + return createLocal(input * 1000); + } + + function createInZone() { + return createLocal.apply(null, arguments).parseZone(); + } + + function preParsePostFormat(string) { + return string; + } + + var proto$1 = Locale.prototype; + + proto$1.calendar = calendar; + proto$1.longDateFormat = longDateFormat; + proto$1.invalidDate = invalidDate; + proto$1.ordinal = ordinal; + proto$1.preparse = preParsePostFormat; + proto$1.postformat = preParsePostFormat; + proto$1.relativeTime = relativeTime; + proto$1.pastFuture = pastFuture; + proto$1.set = set; + proto$1.eras = localeEras; + proto$1.erasParse = localeErasParse; + proto$1.erasConvertYear = localeErasConvertYear; + proto$1.erasAbbrRegex = erasAbbrRegex; + proto$1.erasNameRegex = erasNameRegex; + proto$1.erasNarrowRegex = erasNarrowRegex; + + proto$1.months = localeMonths; + proto$1.monthsShort = localeMonthsShort; + proto$1.monthsParse = localeMonthsParse; + proto$1.monthsRegex = monthsRegex; + proto$1.monthsShortRegex = monthsShortRegex; + proto$1.week = localeWeek; + proto$1.firstDayOfYear = localeFirstDayOfYear; + proto$1.firstDayOfWeek = localeFirstDayOfWeek; + + proto$1.weekdays = localeWeekdays; + proto$1.weekdaysMin = localeWeekdaysMin; + proto$1.weekdaysShort = localeWeekdaysShort; + proto$1.weekdaysParse = localeWeekdaysParse; + + proto$1.weekdaysRegex = weekdaysRegex; + proto$1.weekdaysShortRegex = weekdaysShortRegex; + proto$1.weekdaysMinRegex = weekdaysMinRegex; + + proto$1.isPM = localeIsPM; + proto$1.meridiem = localeMeridiem; + + function get$1(format, index, field, setter) { + var locale = getLocale(), + utc = createUTC().set(setter, index); + return locale[field](utc, format); + } + + function listMonthsImpl(format, index, field) { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + + if (index != null) { + return get$1(format, index, field, 'month'); + } + + var i, + out = []; + for (i = 0; i < 12; i++) { + out[i] = get$1(format, i, field, 'month'); + } + return out; + } + + // () + // (5) + // (fmt, 5) + // (fmt) + // (true) + // (true, 5) + // (true, fmt, 5) + // (true, fmt) + function listWeekdaysImpl(localeSorted, format, index, field) { + if (typeof localeSorted === 'boolean') { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } else { + format = localeSorted; + index = format; + localeSorted = false; + + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } + + var locale = getLocale(), + shift = localeSorted ? locale._week.dow : 0, + i, + out = []; + + if (index != null) { + return get$1(format, (index + shift) % 7, field, 'day'); + } + + for (i = 0; i < 7; i++) { + out[i] = get$1(format, (i + shift) % 7, field, 'day'); + } + return out; + } + + function listMonths(format, index) { + return listMonthsImpl(format, index, 'months'); + } + + function listMonthsShort(format, index) { + return listMonthsImpl(format, index, 'monthsShort'); + } + + function listWeekdays(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); + } + + function listWeekdaysShort(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); + } + + function listWeekdaysMin(localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); + } + + getSetGlobalLocale('en', { + eras: [ + { + since: '0001-01-01', + until: +Infinity, + offset: 1, + name: 'Anno Domini', + narrow: 'AD', + abbr: 'AD', + }, + { + since: '0000-12-31', + until: -Infinity, + offset: 1, + name: 'Before Christ', + narrow: 'BC', + abbr: 'BC', + }, + ], + dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal: function (number) { + var b = number % 10, + output = + toInt((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + }); + + // Side effect imports + + hooks.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + getSetGlobalLocale + ); + hooks.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + getLocale + ); + + var mathAbs = Math.abs; + + function abs() { + var data = this._data; + + this._milliseconds = mathAbs(this._milliseconds); + this._days = mathAbs(this._days); + this._months = mathAbs(this._months); + + data.milliseconds = mathAbs(data.milliseconds); + data.seconds = mathAbs(data.seconds); + data.minutes = mathAbs(data.minutes); + data.hours = mathAbs(data.hours); + data.months = mathAbs(data.months); + data.years = mathAbs(data.years); + + return this; + } + + function addSubtract$1(duration, input, value, direction) { + var other = createDuration(input, value); + + duration._milliseconds += direction * other._milliseconds; + duration._days += direction * other._days; + duration._months += direction * other._months; + + return duration._bubble(); + } + + // supports only 2.0-style add(1, 's') or add(duration) + function add$1(input, value) { + return addSubtract$1(this, input, value, 1); + } + + // supports only 2.0-style subtract(1, 's') or subtract(duration) + function subtract$1(input, value) { + return addSubtract$1(this, input, value, -1); + } + + function absCeil(number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } + } + + function bubble() { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, + minutes, + hours, + years, + monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if ( + !( + (milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0) + ) + ) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absFloor(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absFloor(seconds / 60); + data.minutes = minutes % 60; + + hours = absFloor(minutes / 60); + data.hours = hours % 24; + + days += absFloor(hours / 24); + + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + + return this; + } + + function daysToMonths(days) { + // 400 years have 146097 days (taking into account leap year rules) + // 400 years have 12 months === 4800 + return (days * 4800) / 146097; + } + + function monthsToDays(months) { + // the reverse of daysToMonths + return (months * 146097) / 4800; + } + + function as(units) { + if (!this.isValid()) { + return NaN; + } + var days, + months, + milliseconds = this._milliseconds; + + units = normalizeUnits(units); + + if (units === 'month' || units === 'quarter' || units === 'year') { + days = this._days + milliseconds / 864e5; + months = this._months + daysToMonths(days); + switch (units) { + case 'month': + return months; + case 'quarter': + return months / 3; + case 'year': + return months / 12; + } + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(monthsToDays(this._months)); + switch (units) { + case 'week': + return days / 7 + milliseconds / 6048e5; + case 'day': + return days + milliseconds / 864e5; + case 'hour': + return days * 24 + milliseconds / 36e5; + case 'minute': + return days * 1440 + milliseconds / 6e4; + case 'second': + return days * 86400 + milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': + return Math.floor(days * 864e5) + milliseconds; + default: + throw new Error('Unknown unit ' + units); + } + } + } + + // TODO: Use this.as('ms')? + function valueOf$1() { + if (!this.isValid()) { + return NaN; + } + return ( + this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6 + ); + } + + function makeAs(alias) { + return function () { + return this.as(alias); + }; + } + + var asMilliseconds = makeAs('ms'), + asSeconds = makeAs('s'), + asMinutes = makeAs('m'), + asHours = makeAs('h'), + asDays = makeAs('d'), + asWeeks = makeAs('w'), + asMonths = makeAs('M'), + asQuarters = makeAs('Q'), + asYears = makeAs('y'); + + function clone$1() { + return createDuration(this); + } + + function get$2(units) { + units = normalizeUnits(units); + return this.isValid() ? this[units + 's']() : NaN; + } + + function makeGetter(name) { + return function () { + return this.isValid() ? this._data[name] : NaN; + }; + } + + var milliseconds = makeGetter('milliseconds'), + seconds = makeGetter('seconds'), + minutes = makeGetter('minutes'), + hours = makeGetter('hours'), + days = makeGetter('days'), + months = makeGetter('months'), + years = makeGetter('years'); + + function weeks() { + return absFloor(this.days() / 7); + } + + var round = Math.round, + thresholds = { + ss: 44, // a few seconds to seconds + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month/week + w: null, // weeks to month + M: 11, // months to year + }; + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) { + var duration = createDuration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + weeks = round(duration.as('w')), + years = round(duration.as('y')), + a = + (seconds <= thresholds.ss && ['s', seconds]) || + (seconds < thresholds.s && ['ss', seconds]) || + (minutes <= 1 && ['m']) || + (minutes < thresholds.m && ['mm', minutes]) || + (hours <= 1 && ['h']) || + (hours < thresholds.h && ['hh', hours]) || + (days <= 1 && ['d']) || + (days < thresholds.d && ['dd', days]); + + if (thresholds.w != null) { + a = + a || + (weeks <= 1 && ['w']) || + (weeks < thresholds.w && ['ww', weeks]); + } + a = a || + (months <= 1 && ['M']) || + (months < thresholds.M && ['MM', months]) || + (years <= 1 && ['y']) || ['yy', years]; + + a[2] = withoutSuffix; + a[3] = +posNegDuration > 0; + a[4] = locale; + return substituteTimeAgo.apply(null, a); + } + + // This function allows you to set the rounding function for relative time strings + function getSetRelativeTimeRounding(roundingFunction) { + if (roundingFunction === undefined) { + return round; + } + if (typeof roundingFunction === 'function') { + round = roundingFunction; + return true; + } + return false; + } + + // This function allows you to set a threshold for relative time strings + function getSetRelativeTimeThreshold(threshold, limit) { + if (thresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return thresholds[threshold]; + } + thresholds[threshold] = limit; + if (threshold === 's') { + thresholds.ss = limit - 1; + } + return true; + } + + function humanize(argWithSuffix, argThresholds) { + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var withSuffix = false, + th = thresholds, + locale, + output; + + if (typeof argWithSuffix === 'object') { + argThresholds = argWithSuffix; + argWithSuffix = false; + } + if (typeof argWithSuffix === 'boolean') { + withSuffix = argWithSuffix; + } + if (typeof argThresholds === 'object') { + th = Object.assign({}, thresholds, argThresholds); + if (argThresholds.s != null && argThresholds.ss == null) { + th.ss = argThresholds.s - 1; + } + } + + locale = this.localeData(); + output = relativeTime$1(this, !withSuffix, th, locale); + + if (withSuffix) { + output = locale.pastFuture(+this, output); + } + + return locale.postformat(output); + } + + var abs$1 = Math.abs; + + function sign(x) { + return (x > 0) - (x < 0) || +x; + } + + function toISOString$1() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var seconds = abs$1(this._milliseconds) / 1000, + days = abs$1(this._days), + months = abs$1(this._months), + minutes, + hours, + years, + s, + total = this.asSeconds(), + totalSign, + ymSign, + daysSign, + hmsSign; + + if (!total) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : ''; + + totalSign = total < 0 ? '-' : ''; + ymSign = sign(this._months) !== sign(total) ? '-' : ''; + daysSign = sign(this._days) !== sign(total) ? '-' : ''; + hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : ''; + + return ( + totalSign + + 'P' + + (years ? ymSign + years + 'Y' : '') + + (months ? ymSign + months + 'M' : '') + + (days ? daysSign + days + 'D' : '') + + (hours || minutes || seconds ? 'T' : '') + + (hours ? hmsSign + hours + 'H' : '') + + (minutes ? hmsSign + minutes + 'M' : '') + + (seconds ? hmsSign + s + 'S' : '') + ); + } + + var proto$2 = Duration.prototype; + + proto$2.isValid = isValid$1; + proto$2.abs = abs; + proto$2.add = add$1; + proto$2.subtract = subtract$1; + proto$2.as = as; + proto$2.asMilliseconds = asMilliseconds; + proto$2.asSeconds = asSeconds; + proto$2.asMinutes = asMinutes; + proto$2.asHours = asHours; + proto$2.asDays = asDays; + proto$2.asWeeks = asWeeks; + proto$2.asMonths = asMonths; + proto$2.asQuarters = asQuarters; + proto$2.asYears = asYears; + proto$2.valueOf = valueOf$1; + proto$2._bubble = bubble; + proto$2.clone = clone$1; + proto$2.get = get$2; + proto$2.milliseconds = milliseconds; + proto$2.seconds = seconds; + proto$2.minutes = minutes; + proto$2.hours = hours; + proto$2.days = days; + proto$2.weeks = weeks; + proto$2.months = months; + proto$2.years = years; + proto$2.humanize = humanize; + proto$2.toISOString = toISOString$1; + proto$2.toString = toISOString$1; + proto$2.toJSON = toISOString$1; + proto$2.locale = locale; + proto$2.localeData = localeData; + + proto$2.toIsoString = deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', + toISOString$1 + ); + proto$2.lang = lang; + + // FORMATTING + + addFormatToken('X', 0, 0, 'unix'); + addFormatToken('x', 0, 0, 'valueOf'); + + // PARSING + + addRegexToken('x', matchSigned); + addRegexToken('X', matchTimestamp); + addParseToken('X', function (input, array, config) { + config._d = new Date(parseFloat(input) * 1000); + }); + addParseToken('x', function (input, array, config) { + config._d = new Date(toInt(input)); + }); + + //! moment.js + + hooks.version = '2.29.4'; + + setHookCallback(createLocal); + + hooks.fn = proto; + hooks.min = min; + hooks.max = max; + hooks.now = now; + hooks.utc = createUTC; + hooks.unix = createUnix; + hooks.months = listMonths; + hooks.isDate = isDate; + hooks.locale = getSetGlobalLocale; + hooks.invalid = createInvalid; + hooks.duration = createDuration; + hooks.isMoment = isMoment; + hooks.weekdays = listWeekdays; + hooks.parseZone = createInZone; + hooks.localeData = getLocale; + hooks.isDuration = isDuration; + hooks.monthsShort = listMonthsShort; + hooks.weekdaysMin = listWeekdaysMin; + hooks.defineLocale = defineLocale; + hooks.updateLocale = updateLocale; + hooks.locales = listLocales; + hooks.weekdaysShort = listWeekdaysShort; + hooks.normalizeUnits = normalizeUnits; + hooks.relativeTimeRounding = getSetRelativeTimeRounding; + hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; + hooks.calendarFormat = getCalendarFormat; + hooks.prototype = proto; + + // currently HTML5 input type only supports 24-hour formats + hooks.HTML5_FMT = { + DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // + DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // + DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // + DATE: 'YYYY-MM-DD', // + TIME: 'HH:mm', // + TIME_SECONDS: 'HH:mm:ss', // + TIME_MS: 'HH:mm:ss.SSS', // + WEEK: 'GGGG-[W]WW', // + MONTH: 'YYYY-MM', // + }; + + //! moment.js locale configuration + + hooks.defineLocale('af', { + months: 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'), + weekdays: 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split( + '_' + ), + weekdaysShort: 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'), + weekdaysMin: 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'), + meridiemParse: /vm|nm/i, + isPM: function (input) { + return /^nm$/i.test(input); + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 12) { + return isLower ? 'vm' : 'VM'; + } else { + return isLower ? 'nm' : 'NM'; + } + }, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Vandag om] LT', + nextDay: '[Môre om] LT', + nextWeek: 'dddd [om] LT', + lastDay: '[Gister om] LT', + lastWeek: '[Laas] dddd [om] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'oor %s', + past: '%s gelede', + s: "'n paar sekondes", + ss: '%d sekondes', + m: "'n minuut", + mm: '%d minute', + h: "'n uur", + hh: '%d ure', + d: "'n dag", + dd: '%d dae', + M: "'n maand", + MM: '%d maande', + y: "'n jaar", + yy: '%d jaar', + }, + dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/, + ordinal: function (number) { + return ( + number + + (number === 1 || number === 8 || number >= 20 ? 'ste' : 'de') + ); // Thanks to Joris Röling : https://github.com/jjupiter + }, + week: { + dow: 1, // Maandag is die eerste dag van die week. + doy: 4, // Die week wat die 4de Januarie bevat is die eerste week van die jaar. + }, + }); + + //! moment.js locale configuration + + var pluralForm = function (n) { + return n === 0 + ? 0 + : n === 1 + ? 1 + : n === 2 + ? 2 + : n % 100 >= 3 && n % 100 <= 10 + ? 3 + : n % 100 >= 11 + ? 4 + : 5; + }, + plurals = { + s: [ + 'أقل من ثانية', + 'ثانية واحدة', + ['ثانيتان', 'ثانيتين'], + '%d ثوان', + '%d ثانية', + '%d ثانية', + ], + m: [ + 'أقل من دقيقة', + 'دقيقة واحدة', + ['دقيقتان', 'دقيقتين'], + '%d دقائق', + '%d دقيقة', + '%d دقيقة', + ], + h: [ + 'أقل من ساعة', + 'ساعة واحدة', + ['ساعتان', 'ساعتين'], + '%d ساعات', + '%d ساعة', + '%d ساعة', + ], + d: [ + 'أقل من يوم', + 'يوم واحد', + ['يومان', 'يومين'], + '%d أيام', + '%d يومًا', + '%d يوم', + ], + M: [ + 'أقل من شهر', + 'شهر واحد', + ['شهران', 'شهرين'], + '%d أشهر', + '%d شهرا', + '%d شهر', + ], + y: [ + 'أقل من عام', + 'عام واحد', + ['عامان', 'عامين'], + '%d أعوام', + '%d عامًا', + '%d عام', + ], + }, + pluralize = function (u) { + return function (number, withoutSuffix, string, isFuture) { + var f = pluralForm(number), + str = plurals[u][pluralForm(number)]; + if (f === 2) { + str = str[withoutSuffix ? 0 : 1]; + } + return str.replace(/%d/i, number); + }; + }, + months$1 = [ + 'جانفي', + 'فيفري', + 'مارس', + 'أفريل', + 'ماي', + 'جوان', + 'جويلية', + 'أوت', + 'سبتمبر', + 'أكتوبر', + 'نوفمبر', + 'ديسمبر', + ]; + + hooks.defineLocale('ar-dz', { + months: months$1, + monthsShort: months$1, + weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'D/\u200FM/\u200FYYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + meridiemParse: /ص|م/, + isPM: function (input) { + return 'م' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ص'; + } else { + return 'م'; + } + }, + calendar: { + sameDay: '[اليوم عند الساعة] LT', + nextDay: '[غدًا عند الساعة] LT', + nextWeek: 'dddd [عند الساعة] LT', + lastDay: '[أمس عند الساعة] LT', + lastWeek: 'dddd [عند الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'بعد %s', + past: 'منذ %s', + s: pluralize('s'), + ss: pluralize('s'), + m: pluralize('m'), + mm: pluralize('m'), + h: pluralize('h'), + hh: pluralize('h'), + d: pluralize('d'), + dd: pluralize('d'), + M: pluralize('M'), + MM: pluralize('M'), + y: pluralize('y'), + yy: pluralize('y'), + }, + postformat: function (string) { + return string.replace(/,/g, '،'); + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ar-kw', { + months: 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split( + '_' + ), + monthsShort: + 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split( + '_' + ), + weekdays: 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[اليوم على الساعة] LT', + nextDay: '[غدا على الساعة] LT', + nextWeek: 'dddd [على الساعة] LT', + lastDay: '[أمس على الساعة] LT', + lastWeek: 'dddd [على الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'في %s', + past: 'منذ %s', + s: 'ثوان', + ss: '%d ثانية', + m: 'دقيقة', + mm: '%d دقائق', + h: 'ساعة', + hh: '%d ساعات', + d: 'يوم', + dd: '%d أيام', + M: 'شهر', + MM: '%d أشهر', + y: 'سنة', + yy: '%d سنوات', + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap = { + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 0: '0', + }, + pluralForm$1 = function (n) { + return n === 0 + ? 0 + : n === 1 + ? 1 + : n === 2 + ? 2 + : n % 100 >= 3 && n % 100 <= 10 + ? 3 + : n % 100 >= 11 + ? 4 + : 5; + }, + plurals$1 = { + s: [ + 'أقل من ثانية', + 'ثانية واحدة', + ['ثانيتان', 'ثانيتين'], + '%d ثوان', + '%d ثانية', + '%d ثانية', + ], + m: [ + 'أقل من دقيقة', + 'دقيقة واحدة', + ['دقيقتان', 'دقيقتين'], + '%d دقائق', + '%d دقيقة', + '%d دقيقة', + ], + h: [ + 'أقل من ساعة', + 'ساعة واحدة', + ['ساعتان', 'ساعتين'], + '%d ساعات', + '%d ساعة', + '%d ساعة', + ], + d: [ + 'أقل من يوم', + 'يوم واحد', + ['يومان', 'يومين'], + '%d أيام', + '%d يومًا', + '%d يوم', + ], + M: [ + 'أقل من شهر', + 'شهر واحد', + ['شهران', 'شهرين'], + '%d أشهر', + '%d شهرا', + '%d شهر', + ], + y: [ + 'أقل من عام', + 'عام واحد', + ['عامان', 'عامين'], + '%d أعوام', + '%d عامًا', + '%d عام', + ], + }, + pluralize$1 = function (u) { + return function (number, withoutSuffix, string, isFuture) { + var f = pluralForm$1(number), + str = plurals$1[u][pluralForm$1(number)]; + if (f === 2) { + str = str[withoutSuffix ? 0 : 1]; + } + return str.replace(/%d/i, number); + }; + }, + months$2 = [ + 'يناير', + 'فبراير', + 'مارس', + 'أبريل', + 'مايو', + 'يونيو', + 'يوليو', + 'أغسطس', + 'سبتمبر', + 'أكتوبر', + 'نوفمبر', + 'ديسمبر', + ]; + + hooks.defineLocale('ar-ly', { + months: months$2, + monthsShort: months$2, + weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'D/\u200FM/\u200FYYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + meridiemParse: /ص|م/, + isPM: function (input) { + return 'م' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ص'; + } else { + return 'م'; + } + }, + calendar: { + sameDay: '[اليوم عند الساعة] LT', + nextDay: '[غدًا عند الساعة] LT', + nextWeek: 'dddd [عند الساعة] LT', + lastDay: '[أمس عند الساعة] LT', + lastWeek: 'dddd [عند الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'بعد %s', + past: 'منذ %s', + s: pluralize$1('s'), + ss: pluralize$1('s'), + m: pluralize$1('m'), + mm: pluralize$1('m'), + h: pluralize$1('h'), + hh: pluralize$1('h'), + d: pluralize$1('d'), + dd: pluralize$1('d'), + M: pluralize$1('M'), + MM: pluralize$1('M'), + y: pluralize$1('y'), + yy: pluralize$1('y'), + }, + preparse: function (string) { + return string.replace(/،/g, ','); + }, + postformat: function (string) { + return string + .replace(/\d/g, function (match) { + return symbolMap[match]; + }) + .replace(/,/g, '،'); + }, + week: { + dow: 6, // Saturday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ar-ma', { + months: 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split( + '_' + ), + monthsShort: + 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split( + '_' + ), + weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[اليوم على الساعة] LT', + nextDay: '[غدا على الساعة] LT', + nextWeek: 'dddd [على الساعة] LT', + lastDay: '[أمس على الساعة] LT', + lastWeek: 'dddd [على الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'في %s', + past: 'منذ %s', + s: 'ثوان', + ss: '%d ثانية', + m: 'دقيقة', + mm: '%d دقائق', + h: 'ساعة', + hh: '%d ساعات', + d: 'يوم', + dd: '%d أيام', + M: 'شهر', + MM: '%d أشهر', + y: 'سنة', + yy: '%d سنوات', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$1 = { + 1: '١', + 2: '٢', + 3: '٣', + 4: '٤', + 5: '٥', + 6: '٦', + 7: '٧', + 8: '٨', + 9: '٩', + 0: '٠', + }, + numberMap = { + '١': '1', + '٢': '2', + '٣': '3', + '٤': '4', + '٥': '5', + '٦': '6', + '٧': '7', + '٨': '8', + '٩': '9', + '٠': '0', + }; + + hooks.defineLocale('ar-sa', { + months: 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split( + '_' + ), + monthsShort: + 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split( + '_' + ), + weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + meridiemParse: /ص|م/, + isPM: function (input) { + return 'م' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ص'; + } else { + return 'م'; + } + }, + calendar: { + sameDay: '[اليوم على الساعة] LT', + nextDay: '[غدا على الساعة] LT', + nextWeek: 'dddd [على الساعة] LT', + lastDay: '[أمس على الساعة] LT', + lastWeek: 'dddd [على الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'في %s', + past: 'منذ %s', + s: 'ثوان', + ss: '%d ثانية', + m: 'دقيقة', + mm: '%d دقائق', + h: 'ساعة', + hh: '%d ساعات', + d: 'يوم', + dd: '%d أيام', + M: 'شهر', + MM: '%d أشهر', + y: 'سنة', + yy: '%d سنوات', + }, + preparse: function (string) { + return string + .replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) { + return numberMap[match]; + }) + .replace(/،/g, ','); + }, + postformat: function (string) { + return string + .replace(/\d/g, function (match) { + return symbolMap$1[match]; + }) + .replace(/,/g, '،'); + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ar-tn', { + months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split( + '_' + ), + monthsShort: + 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split( + '_' + ), + weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[اليوم على الساعة] LT', + nextDay: '[غدا على الساعة] LT', + nextWeek: 'dddd [على الساعة] LT', + lastDay: '[أمس على الساعة] LT', + lastWeek: 'dddd [على الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'في %s', + past: 'منذ %s', + s: 'ثوان', + ss: '%d ثانية', + m: 'دقيقة', + mm: '%d دقائق', + h: 'ساعة', + hh: '%d ساعات', + d: 'يوم', + dd: '%d أيام', + M: 'شهر', + MM: '%d أشهر', + y: 'سنة', + yy: '%d سنوات', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$2 = { + 1: '١', + 2: '٢', + 3: '٣', + 4: '٤', + 5: '٥', + 6: '٦', + 7: '٧', + 8: '٨', + 9: '٩', + 0: '٠', + }, + numberMap$1 = { + '١': '1', + '٢': '2', + '٣': '3', + '٤': '4', + '٥': '5', + '٦': '6', + '٧': '7', + '٨': '8', + '٩': '9', + '٠': '0', + }, + pluralForm$2 = function (n) { + return n === 0 + ? 0 + : n === 1 + ? 1 + : n === 2 + ? 2 + : n % 100 >= 3 && n % 100 <= 10 + ? 3 + : n % 100 >= 11 + ? 4 + : 5; + }, + plurals$2 = { + s: [ + 'أقل من ثانية', + 'ثانية واحدة', + ['ثانيتان', 'ثانيتين'], + '%d ثوان', + '%d ثانية', + '%d ثانية', + ], + m: [ + 'أقل من دقيقة', + 'دقيقة واحدة', + ['دقيقتان', 'دقيقتين'], + '%d دقائق', + '%d دقيقة', + '%d دقيقة', + ], + h: [ + 'أقل من ساعة', + 'ساعة واحدة', + ['ساعتان', 'ساعتين'], + '%d ساعات', + '%d ساعة', + '%d ساعة', + ], + d: [ + 'أقل من يوم', + 'يوم واحد', + ['يومان', 'يومين'], + '%d أيام', + '%d يومًا', + '%d يوم', + ], + M: [ + 'أقل من شهر', + 'شهر واحد', + ['شهران', 'شهرين'], + '%d أشهر', + '%d شهرا', + '%d شهر', + ], + y: [ + 'أقل من عام', + 'عام واحد', + ['عامان', 'عامين'], + '%d أعوام', + '%d عامًا', + '%d عام', + ], + }, + pluralize$2 = function (u) { + return function (number, withoutSuffix, string, isFuture) { + var f = pluralForm$2(number), + str = plurals$2[u][pluralForm$2(number)]; + if (f === 2) { + str = str[withoutSuffix ? 0 : 1]; + } + return str.replace(/%d/i, number); + }; + }, + months$3 = [ + 'يناير', + 'فبراير', + 'مارس', + 'أبريل', + 'مايو', + 'يونيو', + 'يوليو', + 'أغسطس', + 'سبتمبر', + 'أكتوبر', + 'نوفمبر', + 'ديسمبر', + ]; + + hooks.defineLocale('ar', { + months: months$3, + monthsShort: months$3, + weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), + weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), + weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'D/\u200FM/\u200FYYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + meridiemParse: /ص|م/, + isPM: function (input) { + return 'م' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ص'; + } else { + return 'م'; + } + }, + calendar: { + sameDay: '[اليوم عند الساعة] LT', + nextDay: '[غدًا عند الساعة] LT', + nextWeek: 'dddd [عند الساعة] LT', + lastDay: '[أمس عند الساعة] LT', + lastWeek: 'dddd [عند الساعة] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'بعد %s', + past: 'منذ %s', + s: pluralize$2('s'), + ss: pluralize$2('s'), + m: pluralize$2('m'), + mm: pluralize$2('m'), + h: pluralize$2('h'), + hh: pluralize$2('h'), + d: pluralize$2('d'), + dd: pluralize$2('d'), + M: pluralize$2('M'), + MM: pluralize$2('M'), + y: pluralize$2('y'), + yy: pluralize$2('y'), + }, + preparse: function (string) { + return string + .replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) { + return numberMap$1[match]; + }) + .replace(/،/g, ','); + }, + postformat: function (string) { + return string + .replace(/\d/g, function (match) { + return symbolMap$2[match]; + }) + .replace(/,/g, '،'); + }, + week: { + dow: 6, // Saturday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var suffixes = { + 1: '-inci', + 5: '-inci', + 8: '-inci', + 70: '-inci', + 80: '-inci', + 2: '-nci', + 7: '-nci', + 20: '-nci', + 50: '-nci', + 3: '-üncü', + 4: '-üncü', + 100: '-üncü', + 6: '-ncı', + 9: '-uncu', + 10: '-uncu', + 30: '-uncu', + 60: '-ıncı', + 90: '-ıncı', + }; + + hooks.defineLocale('az', { + months: 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split( + '_' + ), + monthsShort: 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'), + weekdays: + 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split( + '_' + ), + weekdaysShort: 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'), + weekdaysMin: 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[bugün saat] LT', + nextDay: '[sabah saat] LT', + nextWeek: '[gələn həftə] dddd [saat] LT', + lastDay: '[dünən] LT', + lastWeek: '[keçən həftə] dddd [saat] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s sonra', + past: '%s əvvəl', + s: 'bir neçə saniyə', + ss: '%d saniyə', + m: 'bir dəqiqə', + mm: '%d dəqiqə', + h: 'bir saat', + hh: '%d saat', + d: 'bir gün', + dd: '%d gün', + M: 'bir ay', + MM: '%d ay', + y: 'bir il', + yy: '%d il', + }, + meridiemParse: /gecə|səhər|gündüz|axşam/, + isPM: function (input) { + return /^(gündüz|axşam)$/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'gecə'; + } else if (hour < 12) { + return 'səhər'; + } else if (hour < 17) { + return 'gündüz'; + } else { + return 'axşam'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/, + ordinal: function (number) { + if (number === 0) { + // special case for zero + return number + '-ıncı'; + } + var a = number % 10, + b = (number % 100) - a, + c = number >= 100 ? 100 : null; + return number + (suffixes[a] || suffixes[b] || suffixes[c]); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function plural(word, num) { + var forms = word.split('_'); + return num % 10 === 1 && num % 100 !== 11 + ? forms[0] + : num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) + ? forms[1] + : forms[2]; + } + function relativeTimeWithPlural(number, withoutSuffix, key) { + var format = { + ss: withoutSuffix ? 'секунда_секунды_секунд' : 'секунду_секунды_секунд', + mm: withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін', + hh: withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін', + dd: 'дзень_дні_дзён', + MM: 'месяц_месяцы_месяцаў', + yy: 'год_гады_гадоў', + }; + if (key === 'm') { + return withoutSuffix ? 'хвіліна' : 'хвіліну'; + } else if (key === 'h') { + return withoutSuffix ? 'гадзіна' : 'гадзіну'; + } else { + return number + ' ' + plural(format[key], +number); + } + } + + hooks.defineLocale('be', { + months: { + format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split( + '_' + ), + standalone: + 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split( + '_' + ), + }, + monthsShort: + 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'), + weekdays: { + format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split( + '_' + ), + standalone: + 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split( + '_' + ), + isFormat: /\[ ?[Ууў] ?(?:мінулую|наступную)? ?\] ?dddd/, + }, + weekdaysShort: 'нд_пн_ат_ср_чц_пт_сб'.split('_'), + weekdaysMin: 'нд_пн_ат_ср_чц_пт_сб'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY г.', + LLL: 'D MMMM YYYY г., HH:mm', + LLLL: 'dddd, D MMMM YYYY г., HH:mm', + }, + calendar: { + sameDay: '[Сёння ў] LT', + nextDay: '[Заўтра ў] LT', + lastDay: '[Учора ў] LT', + nextWeek: function () { + return '[У] dddd [ў] LT'; + }, + lastWeek: function () { + switch (this.day()) { + case 0: + case 3: + case 5: + case 6: + return '[У мінулую] dddd [ў] LT'; + case 1: + case 2: + case 4: + return '[У мінулы] dddd [ў] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'праз %s', + past: '%s таму', + s: 'некалькі секунд', + m: relativeTimeWithPlural, + mm: relativeTimeWithPlural, + h: relativeTimeWithPlural, + hh: relativeTimeWithPlural, + d: 'дзень', + dd: relativeTimeWithPlural, + M: 'месяц', + MM: relativeTimeWithPlural, + y: 'год', + yy: relativeTimeWithPlural, + }, + meridiemParse: /ночы|раніцы|дня|вечара/, + isPM: function (input) { + return /^(дня|вечара)$/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'ночы'; + } else if (hour < 12) { + return 'раніцы'; + } else if (hour < 17) { + return 'дня'; + } else { + return 'вечара'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}-(і|ы|га)/, + ordinal: function (number, period) { + switch (period) { + case 'M': + case 'd': + case 'DDD': + case 'w': + case 'W': + return (number % 10 === 2 || number % 10 === 3) && + number % 100 !== 12 && + number % 100 !== 13 + ? number + '-і' + : number + '-ы'; + case 'D': + return number + '-га'; + default: + return number; + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('bg', { + months: 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split( + '_' + ), + monthsShort: 'яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'), + weekdays: 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split( + '_' + ), + weekdaysShort: 'нед_пон_вто_сря_чет_пет_съб'.split('_'), + weekdaysMin: 'нд_пн_вт_ср_чт_пт_сб'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'D.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY H:mm', + LLLL: 'dddd, D MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[Днес в] LT', + nextDay: '[Утре в] LT', + nextWeek: 'dddd [в] LT', + lastDay: '[Вчера в] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + case 3: + case 6: + return '[Миналата] dddd [в] LT'; + case 1: + case 2: + case 4: + case 5: + return '[Миналия] dddd [в] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'след %s', + past: 'преди %s', + s: 'няколко секунди', + ss: '%d секунди', + m: 'минута', + mm: '%d минути', + h: 'час', + hh: '%d часа', + d: 'ден', + dd: '%d дена', + w: 'седмица', + ww: '%d седмици', + M: 'месец', + MM: '%d месеца', + y: 'година', + yy: '%d години', + }, + dayOfMonthOrdinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, + ordinal: function (number) { + var lastDigit = number % 10, + last2Digits = number % 100; + if (number === 0) { + return number + '-ев'; + } else if (last2Digits === 0) { + return number + '-ен'; + } else if (last2Digits > 10 && last2Digits < 20) { + return number + '-ти'; + } else if (lastDigit === 1) { + return number + '-ви'; + } else if (lastDigit === 2) { + return number + '-ри'; + } else if (lastDigit === 7 || lastDigit === 8) { + return number + '-ми'; + } else { + return number + '-ти'; + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('bm', { + months: 'Zanwuyekalo_Fewuruyekalo_Marisikalo_Awirilikalo_Mɛkalo_Zuwɛnkalo_Zuluyekalo_Utikalo_Sɛtanburukalo_ɔkutɔburukalo_Nowanburukalo_Desanburukalo'.split( + '_' + ), + monthsShort: 'Zan_Few_Mar_Awi_Mɛ_Zuw_Zul_Uti_Sɛt_ɔku_Now_Des'.split('_'), + weekdays: 'Kari_Ntɛnɛn_Tarata_Araba_Alamisa_Juma_Sibiri'.split('_'), + weekdaysShort: 'Kar_Ntɛ_Tar_Ara_Ala_Jum_Sib'.split('_'), + weekdaysMin: 'Ka_Nt_Ta_Ar_Al_Ju_Si'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'MMMM [tile] D [san] YYYY', + LLL: 'MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm', + LLLL: 'dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm', + }, + calendar: { + sameDay: '[Bi lɛrɛ] LT', + nextDay: '[Sini lɛrɛ] LT', + nextWeek: 'dddd [don lɛrɛ] LT', + lastDay: '[Kunu lɛrɛ] LT', + lastWeek: 'dddd [tɛmɛnen lɛrɛ] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s kɔnɔ', + past: 'a bɛ %s bɔ', + s: 'sanga dama dama', + ss: 'sekondi %d', + m: 'miniti kelen', + mm: 'miniti %d', + h: 'lɛrɛ kelen', + hh: 'lɛrɛ %d', + d: 'tile kelen', + dd: 'tile %d', + M: 'kalo kelen', + MM: 'kalo %d', + y: 'san kelen', + yy: 'san %d', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$3 = { + 1: '১', + 2: '২', + 3: '৩', + 4: '৪', + 5: '৫', + 6: '৬', + 7: '৭', + 8: '৮', + 9: '৯', + 0: '০', + }, + numberMap$2 = { + '১': '1', + '২': '2', + '৩': '3', + '৪': '4', + '৫': '5', + '৬': '6', + '৭': '7', + '৮': '8', + '৯': '9', + '০': '0', + }; + + hooks.defineLocale('bn-bd', { + months: 'জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split( + '_' + ), + monthsShort: + 'জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে'.split( + '_' + ), + weekdays: 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split( + '_' + ), + weekdaysShort: 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'), + weekdaysMin: 'রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি'.split('_'), + longDateFormat: { + LT: 'A h:mm সময়', + LTS: 'A h:mm:ss সময়', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm সময়', + LLLL: 'dddd, D MMMM YYYY, A h:mm সময়', + }, + calendar: { + sameDay: '[আজ] LT', + nextDay: '[আগামীকাল] LT', + nextWeek: 'dddd, LT', + lastDay: '[গতকাল] LT', + lastWeek: '[গত] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s পরে', + past: '%s আগে', + s: 'কয়েক সেকেন্ড', + ss: '%d সেকেন্ড', + m: 'এক মিনিট', + mm: '%d মিনিট', + h: 'এক ঘন্টা', + hh: '%d ঘন্টা', + d: 'এক দিন', + dd: '%d দিন', + M: 'এক মাস', + MM: '%d মাস', + y: 'এক বছর', + yy: '%d বছর', + }, + preparse: function (string) { + return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) { + return numberMap$2[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$3[match]; + }); + }, + + meridiemParse: /রাত|ভোর|সকাল|দুপুর|বিকাল|সন্ধ্যা|রাত/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'রাত') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'ভোর') { + return hour; + } else if (meridiem === 'সকাল') { + return hour; + } else if (meridiem === 'দুপুর') { + return hour >= 3 ? hour : hour + 12; + } else if (meridiem === 'বিকাল') { + return hour + 12; + } else if (meridiem === 'সন্ধ্যা') { + return hour + 12; + } + }, + + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'রাত'; + } else if (hour < 6) { + return 'ভোর'; + } else if (hour < 12) { + return 'সকাল'; + } else if (hour < 15) { + return 'দুপুর'; + } else if (hour < 18) { + return 'বিকাল'; + } else if (hour < 20) { + return 'সন্ধ্যা'; + } else { + return 'রাত'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$4 = { + 1: '১', + 2: '২', + 3: '৩', + 4: '৪', + 5: '৫', + 6: '৬', + 7: '৭', + 8: '৮', + 9: '৯', + 0: '০', + }, + numberMap$3 = { + '১': '1', + '২': '2', + '৩': '3', + '৪': '4', + '৫': '5', + '৬': '6', + '৭': '7', + '৮': '8', + '৯': '9', + '০': '0', + }; + + hooks.defineLocale('bn', { + months: 'জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split( + '_' + ), + monthsShort: + 'জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে'.split( + '_' + ), + weekdays: 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার'.split( + '_' + ), + weekdaysShort: 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি'.split('_'), + weekdaysMin: 'রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি'.split('_'), + longDateFormat: { + LT: 'A h:mm সময়', + LTS: 'A h:mm:ss সময়', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm সময়', + LLLL: 'dddd, D MMMM YYYY, A h:mm সময়', + }, + calendar: { + sameDay: '[আজ] LT', + nextDay: '[আগামীকাল] LT', + nextWeek: 'dddd, LT', + lastDay: '[গতকাল] LT', + lastWeek: '[গত] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s পরে', + past: '%s আগে', + s: 'কয়েক সেকেন্ড', + ss: '%d সেকেন্ড', + m: 'এক মিনিট', + mm: '%d মিনিট', + h: 'এক ঘন্টা', + hh: '%d ঘন্টা', + d: 'এক দিন', + dd: '%d দিন', + M: 'এক মাস', + MM: '%d মাস', + y: 'এক বছর', + yy: '%d বছর', + }, + preparse: function (string) { + return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) { + return numberMap$3[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$4[match]; + }); + }, + meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if ( + (meridiem === 'রাত' && hour >= 4) || + (meridiem === 'দুপুর' && hour < 5) || + meridiem === 'বিকাল' + ) { + return hour + 12; + } else { + return hour; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'রাত'; + } else if (hour < 10) { + return 'সকাল'; + } else if (hour < 17) { + return 'দুপুর'; + } else if (hour < 20) { + return 'বিকাল'; + } else { + return 'রাত'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$5 = { + 1: '༡', + 2: '༢', + 3: '༣', + 4: '༤', + 5: '༥', + 6: '༦', + 7: '༧', + 8: '༨', + 9: '༩', + 0: '༠', + }, + numberMap$4 = { + '༡': '1', + '༢': '2', + '༣': '3', + '༤': '4', + '༥': '5', + '༦': '6', + '༧': '7', + '༨': '8', + '༩': '9', + '༠': '0', + }; + + hooks.defineLocale('bo', { + months: 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split( + '_' + ), + monthsShort: + 'ཟླ་1_ཟླ་2_ཟླ་3_ཟླ་4_ཟླ་5_ཟླ་6_ཟླ་7_ཟླ་8_ཟླ་9_ཟླ་10_ཟླ་11_ཟླ་12'.split( + '_' + ), + monthsShortRegex: /^(ཟླ་\d{1,2})/, + monthsParseExact: true, + weekdays: + 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split( + '_' + ), + weekdaysShort: 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split( + '_' + ), + weekdaysMin: 'ཉི_ཟླ_མིག_ལྷག_ཕུར_སངས_སྤེན'.split('_'), + longDateFormat: { + LT: 'A h:mm', + LTS: 'A h:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm', + LLLL: 'dddd, D MMMM YYYY, A h:mm', + }, + calendar: { + sameDay: '[དི་རིང] LT', + nextDay: '[སང་ཉིན] LT', + nextWeek: '[བདུན་ཕྲག་རྗེས་མ], LT', + lastDay: '[ཁ་སང] LT', + lastWeek: '[བདུན་ཕྲག་མཐའ་མ] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s ལ་', + past: '%s སྔན་ལ', + s: 'ལམ་སང', + ss: '%d སྐར་ཆ།', + m: 'སྐར་མ་གཅིག', + mm: '%d སྐར་མ', + h: 'ཆུ་ཚོད་གཅིག', + hh: '%d ཆུ་ཚོད', + d: 'ཉིན་གཅིག', + dd: '%d ཉིན་', + M: 'ཟླ་བ་གཅིག', + MM: '%d ཟླ་བ', + y: 'ལོ་གཅིག', + yy: '%d ལོ', + }, + preparse: function (string) { + return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) { + return numberMap$4[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$5[match]; + }); + }, + meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if ( + (meridiem === 'མཚན་མོ' && hour >= 4) || + (meridiem === 'ཉིན་གུང' && hour < 5) || + meridiem === 'དགོང་དག' + ) { + return hour + 12; + } else { + return hour; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'མཚན་མོ'; + } else if (hour < 10) { + return 'ཞོགས་ཀས'; + } else if (hour < 17) { + return 'ཉིན་གུང'; + } else if (hour < 20) { + return 'དགོང་དག'; + } else { + return 'མཚན་མོ'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function relativeTimeWithMutation(number, withoutSuffix, key) { + var format = { + mm: 'munutenn', + MM: 'miz', + dd: 'devezh', + }; + return number + ' ' + mutation(format[key], number); + } + function specialMutationForYears(number) { + switch (lastNumber(number)) { + case 1: + case 3: + case 4: + case 5: + case 9: + return number + ' bloaz'; + default: + return number + ' vloaz'; + } + } + function lastNumber(number) { + if (number > 9) { + return lastNumber(number % 10); + } + return number; + } + function mutation(text, number) { + if (number === 2) { + return softMutation(text); + } + return text; + } + function softMutation(text) { + var mutationTable = { + m: 'v', + b: 'v', + d: 'z', + }; + if (mutationTable[text.charAt(0)] === undefined) { + return text; + } + return mutationTable[text.charAt(0)] + text.substring(1); + } + + var monthsParse = [ + /^gen/i, + /^c[ʼ\']hwe/i, + /^meu/i, + /^ebr/i, + /^mae/i, + /^(mez|eve)/i, + /^gou/i, + /^eos/i, + /^gwe/i, + /^her/i, + /^du/i, + /^ker/i, + ], + monthsRegex$1 = + /^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu|gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i, + monthsStrictRegex = + /^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu)/i, + monthsShortStrictRegex = + /^(gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i, + fullWeekdaysParse = [ + /^sul/i, + /^lun/i, + /^meurzh/i, + /^merc[ʼ\']her/i, + /^yaou/i, + /^gwener/i, + /^sadorn/i, + ], + shortWeekdaysParse = [ + /^Sul/i, + /^Lun/i, + /^Meu/i, + /^Mer/i, + /^Yao/i, + /^Gwe/i, + /^Sad/i, + ], + minWeekdaysParse = [ + /^Su/i, + /^Lu/i, + /^Me([^r]|$)/i, + /^Mer/i, + /^Ya/i, + /^Gw/i, + /^Sa/i, + ]; + + hooks.defineLocale('br', { + months: 'Genver_Cʼhwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split( + '_' + ), + monthsShort: 'Gen_Cʼhwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'), + weekdays: 'Sul_Lun_Meurzh_Mercʼher_Yaou_Gwener_Sadorn'.split('_'), + weekdaysShort: 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'), + weekdaysMin: 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'), + weekdaysParse: minWeekdaysParse, + fullWeekdaysParse: fullWeekdaysParse, + shortWeekdaysParse: shortWeekdaysParse, + minWeekdaysParse: minWeekdaysParse, + + monthsRegex: monthsRegex$1, + monthsShortRegex: monthsRegex$1, + monthsStrictRegex: monthsStrictRegex, + monthsShortStrictRegex: monthsShortStrictRegex, + monthsParse: monthsParse, + longMonthsParse: monthsParse, + shortMonthsParse: monthsParse, + + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [a viz] MMMM YYYY', + LLL: 'D [a viz] MMMM YYYY HH:mm', + LLLL: 'dddd, D [a viz] MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Hiziv da] LT', + nextDay: '[Warcʼhoazh da] LT', + nextWeek: 'dddd [da] LT', + lastDay: '[Decʼh da] LT', + lastWeek: 'dddd [paset da] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'a-benn %s', + past: '%s ʼzo', + s: 'un nebeud segondennoù', + ss: '%d eilenn', + m: 'ur vunutenn', + mm: relativeTimeWithMutation, + h: 'un eur', + hh: '%d eur', + d: 'un devezh', + dd: relativeTimeWithMutation, + M: 'ur miz', + MM: relativeTimeWithMutation, + y: 'ur bloaz', + yy: specialMutationForYears, + }, + dayOfMonthOrdinalParse: /\d{1,2}(añ|vet)/, + ordinal: function (number) { + var output = number === 1 ? 'añ' : 'vet'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + meridiemParse: /a.m.|g.m./, // goude merenn | a-raok merenn + isPM: function (token) { + return token === 'g.m.'; + }, + meridiem: function (hour, minute, isLower) { + return hour < 12 ? 'a.m.' : 'g.m.'; + }, + }); + + //! moment.js locale configuration + + function translate(number, withoutSuffix, key) { + var result = number + ' '; + switch (key) { + case 'ss': + if (number === 1) { + result += 'sekunda'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'sekunde'; + } else { + result += 'sekundi'; + } + return result; + case 'm': + return withoutSuffix ? 'jedna minuta' : 'jedne minute'; + case 'mm': + if (number === 1) { + result += 'minuta'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'minute'; + } else { + result += 'minuta'; + } + return result; + case 'h': + return withoutSuffix ? 'jedan sat' : 'jednog sata'; + case 'hh': + if (number === 1) { + result += 'sat'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'sata'; + } else { + result += 'sati'; + } + return result; + case 'dd': + if (number === 1) { + result += 'dan'; + } else { + result += 'dana'; + } + return result; + case 'MM': + if (number === 1) { + result += 'mjesec'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'mjeseca'; + } else { + result += 'mjeseci'; + } + return result; + case 'yy': + if (number === 1) { + result += 'godina'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'godine'; + } else { + result += 'godina'; + } + return result; + } + } + + hooks.defineLocale('bs', { + months: 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split( + '_' + ), + monthsShort: + 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split( + '_' + ), + weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), + weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm', + LLLL: 'dddd, D. MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[danas u] LT', + nextDay: '[sutra u] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[u] [nedjelju] [u] LT'; + case 3: + return '[u] [srijedu] [u] LT'; + case 6: + return '[u] [subotu] [u] LT'; + case 1: + case 2: + case 4: + case 5: + return '[u] dddd [u] LT'; + } + }, + lastDay: '[jučer u] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + case 3: + return '[prošlu] dddd [u] LT'; + case 6: + return '[prošle] [subote] [u] LT'; + case 1: + case 2: + case 4: + case 5: + return '[prošli] dddd [u] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: 'prije %s', + s: 'par sekundi', + ss: translate, + m: translate, + mm: translate, + h: translate, + hh: translate, + d: 'dan', + dd: translate, + M: 'mjesec', + MM: translate, + y: 'godinu', + yy: translate, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ca', { + months: { + standalone: + 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split( + '_' + ), + format: "de gener_de febrer_de març_d'abril_de maig_de juny_de juliol_d'agost_de setembre_d'octubre_de novembre_de desembre".split( + '_' + ), + isFormat: /D[oD]?(\s)+MMMM/, + }, + monthsShort: + 'gen._febr._març_abr._maig_juny_jul._ag._set._oct._nov._des.'.split( + '_' + ), + monthsParseExact: true, + weekdays: + 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split( + '_' + ), + weekdaysShort: 'dg._dl._dt._dc._dj._dv._ds.'.split('_'), + weekdaysMin: 'dg_dl_dt_dc_dj_dv_ds'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM [de] YYYY', + ll: 'D MMM YYYY', + LLL: 'D MMMM [de] YYYY [a les] H:mm', + lll: 'D MMM YYYY, H:mm', + LLLL: 'dddd D MMMM [de] YYYY [a les] H:mm', + llll: 'ddd D MMM YYYY, H:mm', + }, + calendar: { + sameDay: function () { + return '[avui a ' + (this.hours() !== 1 ? 'les' : 'la') + '] LT'; + }, + nextDay: function () { + return '[demà a ' + (this.hours() !== 1 ? 'les' : 'la') + '] LT'; + }, + nextWeek: function () { + return 'dddd [a ' + (this.hours() !== 1 ? 'les' : 'la') + '] LT'; + }, + lastDay: function () { + return '[ahir a ' + (this.hours() !== 1 ? 'les' : 'la') + '] LT'; + }, + lastWeek: function () { + return ( + '[el] dddd [passat a ' + + (this.hours() !== 1 ? 'les' : 'la') + + '] LT' + ); + }, + sameElse: 'L', + }, + relativeTime: { + future: "d'aquí %s", + past: 'fa %s', + s: 'uns segons', + ss: '%d segons', + m: 'un minut', + mm: '%d minuts', + h: 'una hora', + hh: '%d hores', + d: 'un dia', + dd: '%d dies', + M: 'un mes', + MM: '%d mesos', + y: 'un any', + yy: '%d anys', + }, + dayOfMonthOrdinalParse: /\d{1,2}(r|n|t|è|a)/, + ordinal: function (number, period) { + var output = + number === 1 + ? 'r' + : number === 2 + ? 'n' + : number === 3 + ? 'r' + : number === 4 + ? 't' + : 'è'; + if (period === 'w' || period === 'W') { + output = 'a'; + } + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var months$4 = { + format: 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split( + '_' + ), + standalone: + 'ledna_února_března_dubna_května_června_července_srpna_září_října_listopadu_prosince'.split( + '_' + ), + }, + monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_'), + monthsParse$1 = [ + /^led/i, + /^úno/i, + /^bře/i, + /^dub/i, + /^kvě/i, + /^(čvn|červen$|června)/i, + /^(čvc|červenec|července)/i, + /^srp/i, + /^zář/i, + /^říj/i, + /^lis/i, + /^pro/i, + ], + // NOTE: 'červen' is substring of 'červenec'; therefore 'červenec' must precede 'červen' in the regex to be fully matched. + // Otherwise parser matches '1. červenec' as '1. červen' + 'ec'. + monthsRegex$2 = + /^(leden|únor|březen|duben|květen|červenec|července|červen|června|srpen|září|říjen|listopad|prosinec|led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i; + + function plural$1(n) { + return n > 1 && n < 5 && ~~(n / 10) !== 1; + } + function translate$1(number, withoutSuffix, key, isFuture) { + var result = number + ' '; + switch (key) { + case 's': // a few seconds / in a few seconds / a few seconds ago + return withoutSuffix || isFuture ? 'pár sekund' : 'pár sekundami'; + case 'ss': // 9 seconds / in 9 seconds / 9 seconds ago + if (withoutSuffix || isFuture) { + return result + (plural$1(number) ? 'sekundy' : 'sekund'); + } else { + return result + 'sekundami'; + } + case 'm': // a minute / in a minute / a minute ago + return withoutSuffix ? 'minuta' : isFuture ? 'minutu' : 'minutou'; + case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago + if (withoutSuffix || isFuture) { + return result + (plural$1(number) ? 'minuty' : 'minut'); + } else { + return result + 'minutami'; + } + case 'h': // an hour / in an hour / an hour ago + return withoutSuffix ? 'hodina' : isFuture ? 'hodinu' : 'hodinou'; + case 'hh': // 9 hours / in 9 hours / 9 hours ago + if (withoutSuffix || isFuture) { + return result + (plural$1(number) ? 'hodiny' : 'hodin'); + } else { + return result + 'hodinami'; + } + case 'd': // a day / in a day / a day ago + return withoutSuffix || isFuture ? 'den' : 'dnem'; + case 'dd': // 9 days / in 9 days / 9 days ago + if (withoutSuffix || isFuture) { + return result + (plural$1(number) ? 'dny' : 'dní'); + } else { + return result + 'dny'; + } + case 'M': // a month / in a month / a month ago + return withoutSuffix || isFuture ? 'měsíc' : 'měsícem'; + case 'MM': // 9 months / in 9 months / 9 months ago + if (withoutSuffix || isFuture) { + return result + (plural$1(number) ? 'měsíce' : 'měsíců'); + } else { + return result + 'měsíci'; + } + case 'y': // a year / in a year / a year ago + return withoutSuffix || isFuture ? 'rok' : 'rokem'; + case 'yy': // 9 years / in 9 years / 9 years ago + if (withoutSuffix || isFuture) { + return result + (plural$1(number) ? 'roky' : 'let'); + } else { + return result + 'lety'; + } + } + } + + hooks.defineLocale('cs', { + months: months$4, + monthsShort: monthsShort, + monthsRegex: monthsRegex$2, + monthsShortRegex: monthsRegex$2, + // NOTE: 'červen' is substring of 'červenec'; therefore 'červenec' must precede 'červen' in the regex to be fully matched. + // Otherwise parser matches '1. červenec' as '1. červen' + 'ec'. + monthsStrictRegex: + /^(leden|ledna|února|únor|březen|března|duben|dubna|květen|května|červenec|července|červen|června|srpen|srpna|září|říjen|října|listopadu|listopad|prosinec|prosince)/i, + monthsShortStrictRegex: + /^(led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i, + monthsParse: monthsParse$1, + longMonthsParse: monthsParse$1, + shortMonthsParse: monthsParse$1, + weekdays: 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'), + weekdaysShort: 'ne_po_út_st_čt_pá_so'.split('_'), + weekdaysMin: 'ne_po_út_st_čt_pá_so'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm', + LLLL: 'dddd D. MMMM YYYY H:mm', + l: 'D. M. YYYY', + }, + calendar: { + sameDay: '[dnes v] LT', + nextDay: '[zítra v] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[v neděli v] LT'; + case 1: + case 2: + return '[v] dddd [v] LT'; + case 3: + return '[ve středu v] LT'; + case 4: + return '[ve čtvrtek v] LT'; + case 5: + return '[v pátek v] LT'; + case 6: + return '[v sobotu v] LT'; + } + }, + lastDay: '[včera v] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[minulou neděli v] LT'; + case 1: + case 2: + return '[minulé] dddd [v] LT'; + case 3: + return '[minulou středu v] LT'; + case 4: + case 5: + return '[minulý] dddd [v] LT'; + case 6: + return '[minulou sobotu v] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: 'před %s', + s: translate$1, + ss: translate$1, + m: translate$1, + mm: translate$1, + h: translate$1, + hh: translate$1, + d: translate$1, + dd: translate$1, + M: translate$1, + MM: translate$1, + y: translate$1, + yy: translate$1, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('cv', { + months: 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split( + '_' + ), + monthsShort: 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'), + weekdays: + 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split( + '_' + ), + weekdaysShort: 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'), + weekdaysMin: 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD-MM-YYYY', + LL: 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]', + LLL: 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm', + LLLL: 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm', + }, + calendar: { + sameDay: '[Паян] LT [сехетре]', + nextDay: '[Ыран] LT [сехетре]', + lastDay: '[Ӗнер] LT [сехетре]', + nextWeek: '[Ҫитес] dddd LT [сехетре]', + lastWeek: '[Иртнӗ] dddd LT [сехетре]', + sameElse: 'L', + }, + relativeTime: { + future: function (output) { + var affix = /сехет$/i.exec(output) + ? 'рен' + : /ҫул$/i.exec(output) + ? 'тан' + : 'ран'; + return output + affix; + }, + past: '%s каялла', + s: 'пӗр-ик ҫеккунт', + ss: '%d ҫеккунт', + m: 'пӗр минут', + mm: '%d минут', + h: 'пӗр сехет', + hh: '%d сехет', + d: 'пӗр кун', + dd: '%d кун', + M: 'пӗр уйӑх', + MM: '%d уйӑх', + y: 'пӗр ҫул', + yy: '%d ҫул', + }, + dayOfMonthOrdinalParse: /\d{1,2}-мӗш/, + ordinal: '%d-мӗш', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('cy', { + months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split( + '_' + ), + monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split( + '_' + ), + weekdays: + 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split( + '_' + ), + weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'), + weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'), + weekdaysParseExact: true, + // time formats are the same as en-gb + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Heddiw am] LT', + nextDay: '[Yfory am] LT', + nextWeek: 'dddd [am] LT', + lastDay: '[Ddoe am] LT', + lastWeek: 'dddd [diwethaf am] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'mewn %s', + past: '%s yn ôl', + s: 'ychydig eiliadau', + ss: '%d eiliad', + m: 'munud', + mm: '%d munud', + h: 'awr', + hh: '%d awr', + d: 'diwrnod', + dd: '%d diwrnod', + M: 'mis', + MM: '%d mis', + y: 'blwyddyn', + yy: '%d flynedd', + }, + dayOfMonthOrdinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/, + // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh + ordinal: function (number) { + var b = number, + output = '', + lookup = [ + '', + 'af', + 'il', + 'ydd', + 'ydd', + 'ed', + 'ed', + 'ed', + 'fed', + 'fed', + 'fed', // 1af to 10fed + 'eg', + 'fed', + 'eg', + 'eg', + 'fed', + 'eg', + 'eg', + 'fed', + 'eg', + 'fed', // 11eg to 20fed + ]; + if (b > 20) { + if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) { + output = 'fed'; // not 30ain, 70ain or 90ain + } else { + output = 'ain'; + } + } else if (b > 0) { + output = lookup[b]; + } + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('da', { + months: 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split( + '_' + ), + monthsShort: 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), + weekdays: 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), + weekdaysShort: 'søn_man_tir_ons_tor_fre_lør'.split('_'), + weekdaysMin: 'sø_ma_ti_on_to_fr_lø'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY HH:mm', + LLLL: 'dddd [d.] D. MMMM YYYY [kl.] HH:mm', + }, + calendar: { + sameDay: '[i dag kl.] LT', + nextDay: '[i morgen kl.] LT', + nextWeek: 'på dddd [kl.] LT', + lastDay: '[i går kl.] LT', + lastWeek: '[i] dddd[s kl.] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'om %s', + past: '%s siden', + s: 'få sekunder', + ss: '%d sekunder', + m: 'et minut', + mm: '%d minutter', + h: 'en time', + hh: '%d timer', + d: 'en dag', + dd: '%d dage', + M: 'en måned', + MM: '%d måneder', + y: 'et år', + yy: '%d år', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function processRelativeTime(number, withoutSuffix, key, isFuture) { + var format = { + m: ['eine Minute', 'einer Minute'], + h: ['eine Stunde', 'einer Stunde'], + d: ['ein Tag', 'einem Tag'], + dd: [number + ' Tage', number + ' Tagen'], + w: ['eine Woche', 'einer Woche'], + M: ['ein Monat', 'einem Monat'], + MM: [number + ' Monate', number + ' Monaten'], + y: ['ein Jahr', 'einem Jahr'], + yy: [number + ' Jahre', number + ' Jahren'], + }; + return withoutSuffix ? format[key][0] : format[key][1]; + } + + hooks.defineLocale('de-at', { + months: 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split( + '_' + ), + monthsShort: + 'Jän._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'), + monthsParseExact: true, + weekdays: + 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split( + '_' + ), + weekdaysShort: 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), + weekdaysMin: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY HH:mm', + LLLL: 'dddd, D. MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[heute um] LT [Uhr]', + sameElse: 'L', + nextDay: '[morgen um] LT [Uhr]', + nextWeek: 'dddd [um] LT [Uhr]', + lastDay: '[gestern um] LT [Uhr]', + lastWeek: '[letzten] dddd [um] LT [Uhr]', + }, + relativeTime: { + future: 'in %s', + past: 'vor %s', + s: 'ein paar Sekunden', + ss: '%d Sekunden', + m: processRelativeTime, + mm: '%d Minuten', + h: processRelativeTime, + hh: '%d Stunden', + d: processRelativeTime, + dd: processRelativeTime, + w: processRelativeTime, + ww: '%d Wochen', + M: processRelativeTime, + MM: processRelativeTime, + y: processRelativeTime, + yy: processRelativeTime, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function processRelativeTime$1(number, withoutSuffix, key, isFuture) { + var format = { + m: ['eine Minute', 'einer Minute'], + h: ['eine Stunde', 'einer Stunde'], + d: ['ein Tag', 'einem Tag'], + dd: [number + ' Tage', number + ' Tagen'], + w: ['eine Woche', 'einer Woche'], + M: ['ein Monat', 'einem Monat'], + MM: [number + ' Monate', number + ' Monaten'], + y: ['ein Jahr', 'einem Jahr'], + yy: [number + ' Jahre', number + ' Jahren'], + }; + return withoutSuffix ? format[key][0] : format[key][1]; + } + + hooks.defineLocale('de-ch', { + months: 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split( + '_' + ), + monthsShort: + 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'), + monthsParseExact: true, + weekdays: + 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split( + '_' + ), + weekdaysShort: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), + weekdaysMin: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY HH:mm', + LLLL: 'dddd, D. MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[heute um] LT [Uhr]', + sameElse: 'L', + nextDay: '[morgen um] LT [Uhr]', + nextWeek: 'dddd [um] LT [Uhr]', + lastDay: '[gestern um] LT [Uhr]', + lastWeek: '[letzten] dddd [um] LT [Uhr]', + }, + relativeTime: { + future: 'in %s', + past: 'vor %s', + s: 'ein paar Sekunden', + ss: '%d Sekunden', + m: processRelativeTime$1, + mm: '%d Minuten', + h: processRelativeTime$1, + hh: '%d Stunden', + d: processRelativeTime$1, + dd: processRelativeTime$1, + w: processRelativeTime$1, + ww: '%d Wochen', + M: processRelativeTime$1, + MM: processRelativeTime$1, + y: processRelativeTime$1, + yy: processRelativeTime$1, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function processRelativeTime$2(number, withoutSuffix, key, isFuture) { + var format = { + m: ['eine Minute', 'einer Minute'], + h: ['eine Stunde', 'einer Stunde'], + d: ['ein Tag', 'einem Tag'], + dd: [number + ' Tage', number + ' Tagen'], + w: ['eine Woche', 'einer Woche'], + M: ['ein Monat', 'einem Monat'], + MM: [number + ' Monate', number + ' Monaten'], + y: ['ein Jahr', 'einem Jahr'], + yy: [number + ' Jahre', number + ' Jahren'], + }; + return withoutSuffix ? format[key][0] : format[key][1]; + } + + hooks.defineLocale('de', { + months: 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split( + '_' + ), + monthsShort: + 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'), + monthsParseExact: true, + weekdays: + 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split( + '_' + ), + weekdaysShort: 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), + weekdaysMin: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY HH:mm', + LLLL: 'dddd, D. MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[heute um] LT [Uhr]', + sameElse: 'L', + nextDay: '[morgen um] LT [Uhr]', + nextWeek: 'dddd [um] LT [Uhr]', + lastDay: '[gestern um] LT [Uhr]', + lastWeek: '[letzten] dddd [um] LT [Uhr]', + }, + relativeTime: { + future: 'in %s', + past: 'vor %s', + s: 'ein paar Sekunden', + ss: '%d Sekunden', + m: processRelativeTime$2, + mm: '%d Minuten', + h: processRelativeTime$2, + hh: '%d Stunden', + d: processRelativeTime$2, + dd: processRelativeTime$2, + w: processRelativeTime$2, + ww: '%d Wochen', + M: processRelativeTime$2, + MM: processRelativeTime$2, + y: processRelativeTime$2, + yy: processRelativeTime$2, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var months$5 = [ + 'ޖެނުއަރީ', + 'ފެބްރުއަރީ', + 'މާރިޗު', + 'އޭޕްރީލު', + 'މޭ', + 'ޖޫން', + 'ޖުލައި', + 'އޯގަސްޓު', + 'ސެޕްޓެމްބަރު', + 'އޮކްޓޯބަރު', + 'ނޮވެމްބަރު', + 'ޑިސެމްބަރު', + ], + weekdays = [ + 'އާދިއްތަ', + 'ހޯމަ', + 'އަންގާރަ', + 'ބުދަ', + 'ބުރާސްފަތި', + 'ހުކުރު', + 'ހޮނިހިރު', + ]; + + hooks.defineLocale('dv', { + months: months$5, + monthsShort: months$5, + weekdays: weekdays, + weekdaysShort: weekdays, + weekdaysMin: 'އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'D/M/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + meridiemParse: /މކ|މފ/, + isPM: function (input) { + return 'މފ' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'މކ'; + } else { + return 'މފ'; + } + }, + calendar: { + sameDay: '[މިއަދު] LT', + nextDay: '[މާދަމާ] LT', + nextWeek: 'dddd LT', + lastDay: '[އިއްޔެ] LT', + lastWeek: '[ފާއިތުވި] dddd LT', + sameElse: 'L', + }, + relativeTime: { + future: 'ތެރޭގައި %s', + past: 'ކުރިން %s', + s: 'ސިކުންތުކޮޅެއް', + ss: 'd% ސިކުންތު', + m: 'މިނިޓެއް', + mm: 'މިނިޓު %d', + h: 'ގަޑިއިރެއް', + hh: 'ގަޑިއިރު %d', + d: 'ދުވަހެއް', + dd: 'ދުވަސް %d', + M: 'މަހެއް', + MM: 'މަސް %d', + y: 'އަހަރެއް', + yy: 'އަހަރު %d', + }, + preparse: function (string) { + return string.replace(/،/g, ','); + }, + postformat: function (string) { + return string.replace(/,/g, '،'); + }, + week: { + dow: 7, // Sunday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function isFunction$1(input) { + return ( + (typeof Function !== 'undefined' && input instanceof Function) || + Object.prototype.toString.call(input) === '[object Function]' + ); + } + + hooks.defineLocale('el', { + monthsNominativeEl: + 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split( + '_' + ), + monthsGenitiveEl: + 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split( + '_' + ), + months: function (momentToFormat, format) { + if (!momentToFormat) { + return this._monthsNominativeEl; + } else if ( + typeof format === 'string' && + /D/.test(format.substring(0, format.indexOf('MMMM'))) + ) { + // if there is a day number before 'MMMM' + return this._monthsGenitiveEl[momentToFormat.month()]; + } else { + return this._monthsNominativeEl[momentToFormat.month()]; + } + }, + monthsShort: 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'), + weekdays: 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split( + '_' + ), + weekdaysShort: 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'), + weekdaysMin: 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'), + meridiem: function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'μμ' : 'ΜΜ'; + } else { + return isLower ? 'πμ' : 'ΠΜ'; + } + }, + isPM: function (input) { + return (input + '').toLowerCase()[0] === 'μ'; + }, + meridiemParse: /[ΠΜ]\.?Μ?\.?/i, + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY h:mm A', + LLLL: 'dddd, D MMMM YYYY h:mm A', + }, + calendarEl: { + sameDay: '[Σήμερα {}] LT', + nextDay: '[Αύριο {}] LT', + nextWeek: 'dddd [{}] LT', + lastDay: '[Χθες {}] LT', + lastWeek: function () { + switch (this.day()) { + case 6: + return '[το προηγούμενο] dddd [{}] LT'; + default: + return '[την προηγούμενη] dddd [{}] LT'; + } + }, + sameElse: 'L', + }, + calendar: function (key, mom) { + var output = this._calendarEl[key], + hours = mom && mom.hours(); + if (isFunction$1(output)) { + output = output.apply(mom); + } + return output.replace('{}', hours % 12 === 1 ? 'στη' : 'στις'); + }, + relativeTime: { + future: 'σε %s', + past: '%s πριν', + s: 'λίγα δευτερόλεπτα', + ss: '%d δευτερόλεπτα', + m: 'ένα λεπτό', + mm: '%d λεπτά', + h: 'μία ώρα', + hh: '%d ώρες', + d: 'μία μέρα', + dd: '%d μέρες', + M: 'ένας μήνας', + MM: '%d μήνες', + y: 'ένας χρόνος', + yy: '%d χρόνια', + }, + dayOfMonthOrdinalParse: /\d{1,2}η/, + ordinal: '%dη', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4st is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-au', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY h:mm A', + LLLL: 'dddd, D MMMM YYYY h:mm A', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-ca', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'YYYY-MM-DD', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY h:mm A', + LLLL: 'dddd, MMMM D, YYYY h:mm A', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-gb', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-ie', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-il', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-in', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY h:mm A', + LLLL: 'dddd, D MMMM YYYY h:mm A', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 1st is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-nz', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY h:mm A', + LLLL: 'dddd, D MMMM YYYY h:mm A', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('en-sg', { + months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( + '_' + ), + weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Today at] LT', + nextDay: '[Tomorrow at] LT', + nextWeek: 'dddd [at] LT', + lastDay: '[Yesterday at] LT', + lastWeek: '[Last] dddd [at] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'in %s', + past: '%s ago', + s: 'a few seconds', + ss: '%d seconds', + m: 'a minute', + mm: '%d minutes', + h: 'an hour', + hh: '%d hours', + d: 'a day', + dd: '%d days', + M: 'a month', + MM: '%d months', + y: 'a year', + yy: '%d years', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('eo', { + months: 'januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro'.split( + '_' + ), + monthsShort: 'jan_feb_mart_apr_maj_jun_jul_aŭg_sept_okt_nov_dec'.split('_'), + weekdays: 'dimanĉo_lundo_mardo_merkredo_ĵaŭdo_vendredo_sabato'.split('_'), + weekdaysShort: 'dim_lun_mard_merk_ĵaŭ_ven_sab'.split('_'), + weekdaysMin: 'di_lu_ma_me_ĵa_ve_sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: '[la] D[-an de] MMMM, YYYY', + LLL: '[la] D[-an de] MMMM, YYYY HH:mm', + LLLL: 'dddd[n], [la] D[-an de] MMMM, YYYY HH:mm', + llll: 'ddd, [la] D[-an de] MMM, YYYY HH:mm', + }, + meridiemParse: /[ap]\.t\.m/i, + isPM: function (input) { + return input.charAt(0).toLowerCase() === 'p'; + }, + meridiem: function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'p.t.m.' : 'P.T.M.'; + } else { + return isLower ? 'a.t.m.' : 'A.T.M.'; + } + }, + calendar: { + sameDay: '[Hodiaŭ je] LT', + nextDay: '[Morgaŭ je] LT', + nextWeek: 'dddd[n je] LT', + lastDay: '[Hieraŭ je] LT', + lastWeek: '[pasintan] dddd[n je] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'post %s', + past: 'antaŭ %s', + s: 'kelkaj sekundoj', + ss: '%d sekundoj', + m: 'unu minuto', + mm: '%d minutoj', + h: 'unu horo', + hh: '%d horoj', + d: 'unu tago', //ne 'diurno', ĉar estas uzita por proksimumo + dd: '%d tagoj', + M: 'unu monato', + MM: '%d monatoj', + y: 'unu jaro', + yy: '%d jaroj', + }, + dayOfMonthOrdinalParse: /\d{1,2}a/, + ordinal: '%da', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsShortDot = + 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split( + '_' + ), + monthsShort$1 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'), + monthsParse$2 = [ + /^ene/i, + /^feb/i, + /^mar/i, + /^abr/i, + /^may/i, + /^jun/i, + /^jul/i, + /^ago/i, + /^sep/i, + /^oct/i, + /^nov/i, + /^dic/i, + ], + monthsRegex$3 = + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i; + + hooks.defineLocale('es-do', { + months: 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortDot; + } else if (/-MMM-/.test(format)) { + return monthsShort$1[m.month()]; + } else { + return monthsShortDot[m.month()]; + } + }, + monthsRegex: monthsRegex$3, + monthsShortRegex: monthsRegex$3, + monthsStrictRegex: + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i, + monthsShortStrictRegex: + /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i, + monthsParse: monthsParse$2, + longMonthsParse: monthsParse$2, + shortMonthsParse: monthsParse$2, + weekdays: 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), + weekdaysShort: 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), + weekdaysMin: 'do_lu_ma_mi_ju_vi_sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY h:mm A', + LLLL: 'dddd, D [de] MMMM [de] YYYY h:mm A', + }, + calendar: { + sameDay: function () { + return '[hoy a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextDay: function () { + return '[mañana a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextWeek: function () { + return 'dddd [a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastDay: function () { + return '[ayer a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastWeek: function () { + return ( + '[el] dddd [pasado a la' + + (this.hours() !== 1 ? 's' : '') + + '] LT' + ); + }, + sameElse: 'L', + }, + relativeTime: { + future: 'en %s', + past: 'hace %s', + s: 'unos segundos', + ss: '%d segundos', + m: 'un minuto', + mm: '%d minutos', + h: 'una hora', + hh: '%d horas', + d: 'un día', + dd: '%d días', + w: 'una semana', + ww: '%d semanas', + M: 'un mes', + MM: '%d meses', + y: 'un año', + yy: '%d años', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsShortDot$1 = + 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split( + '_' + ), + monthsShort$2 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'), + monthsParse$3 = [ + /^ene/i, + /^feb/i, + /^mar/i, + /^abr/i, + /^may/i, + /^jun/i, + /^jul/i, + /^ago/i, + /^sep/i, + /^oct/i, + /^nov/i, + /^dic/i, + ], + monthsRegex$4 = + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i; + + hooks.defineLocale('es-mx', { + months: 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortDot$1; + } else if (/-MMM-/.test(format)) { + return monthsShort$2[m.month()]; + } else { + return monthsShortDot$1[m.month()]; + } + }, + monthsRegex: monthsRegex$4, + monthsShortRegex: monthsRegex$4, + monthsStrictRegex: + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i, + monthsShortStrictRegex: + /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i, + monthsParse: monthsParse$3, + longMonthsParse: monthsParse$3, + shortMonthsParse: monthsParse$3, + weekdays: 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), + weekdaysShort: 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), + weekdaysMin: 'do_lu_ma_mi_ju_vi_sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY H:mm', + LLLL: 'dddd, D [de] MMMM [de] YYYY H:mm', + }, + calendar: { + sameDay: function () { + return '[hoy a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextDay: function () { + return '[mañana a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextWeek: function () { + return 'dddd [a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastDay: function () { + return '[ayer a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastWeek: function () { + return ( + '[el] dddd [pasado a la' + + (this.hours() !== 1 ? 's' : '') + + '] LT' + ); + }, + sameElse: 'L', + }, + relativeTime: { + future: 'en %s', + past: 'hace %s', + s: 'unos segundos', + ss: '%d segundos', + m: 'un minuto', + mm: '%d minutos', + h: 'una hora', + hh: '%d horas', + d: 'un día', + dd: '%d días', + w: 'una semana', + ww: '%d semanas', + M: 'un mes', + MM: '%d meses', + y: 'un año', + yy: '%d años', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 0, // Sunday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + invalidDate: 'Fecha inválida', + }); + + //! moment.js locale configuration + + var monthsShortDot$2 = + 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split( + '_' + ), + monthsShort$3 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'), + monthsParse$4 = [ + /^ene/i, + /^feb/i, + /^mar/i, + /^abr/i, + /^may/i, + /^jun/i, + /^jul/i, + /^ago/i, + /^sep/i, + /^oct/i, + /^nov/i, + /^dic/i, + ], + monthsRegex$5 = + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i; + + hooks.defineLocale('es-us', { + months: 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortDot$2; + } else if (/-MMM-/.test(format)) { + return monthsShort$3[m.month()]; + } else { + return monthsShortDot$2[m.month()]; + } + }, + monthsRegex: monthsRegex$5, + monthsShortRegex: monthsRegex$5, + monthsStrictRegex: + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i, + monthsShortStrictRegex: + /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i, + monthsParse: monthsParse$4, + longMonthsParse: monthsParse$4, + shortMonthsParse: monthsParse$4, + weekdays: 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), + weekdaysShort: 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), + weekdaysMin: 'do_lu_ma_mi_ju_vi_sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'MM/DD/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY h:mm A', + LLLL: 'dddd, D [de] MMMM [de] YYYY h:mm A', + }, + calendar: { + sameDay: function () { + return '[hoy a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextDay: function () { + return '[mañana a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextWeek: function () { + return 'dddd [a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastDay: function () { + return '[ayer a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastWeek: function () { + return ( + '[el] dddd [pasado a la' + + (this.hours() !== 1 ? 's' : '') + + '] LT' + ); + }, + sameElse: 'L', + }, + relativeTime: { + future: 'en %s', + past: 'hace %s', + s: 'unos segundos', + ss: '%d segundos', + m: 'un minuto', + mm: '%d minutos', + h: 'una hora', + hh: '%d horas', + d: 'un día', + dd: '%d días', + w: 'una semana', + ww: '%d semanas', + M: 'un mes', + MM: '%d meses', + y: 'un año', + yy: '%d años', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsShortDot$3 = + 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split( + '_' + ), + monthsShort$4 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'), + monthsParse$5 = [ + /^ene/i, + /^feb/i, + /^mar/i, + /^abr/i, + /^may/i, + /^jun/i, + /^jul/i, + /^ago/i, + /^sep/i, + /^oct/i, + /^nov/i, + /^dic/i, + ], + monthsRegex$6 = + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i; + + hooks.defineLocale('es', { + months: 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortDot$3; + } else if (/-MMM-/.test(format)) { + return monthsShort$4[m.month()]; + } else { + return monthsShortDot$3[m.month()]; + } + }, + monthsRegex: monthsRegex$6, + monthsShortRegex: monthsRegex$6, + monthsStrictRegex: + /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i, + monthsShortStrictRegex: + /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i, + monthsParse: monthsParse$5, + longMonthsParse: monthsParse$5, + shortMonthsParse: monthsParse$5, + weekdays: 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), + weekdaysShort: 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), + weekdaysMin: 'do_lu_ma_mi_ju_vi_sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY H:mm', + LLLL: 'dddd, D [de] MMMM [de] YYYY H:mm', + }, + calendar: { + sameDay: function () { + return '[hoy a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextDay: function () { + return '[mañana a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + nextWeek: function () { + return 'dddd [a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastDay: function () { + return '[ayer a la' + (this.hours() !== 1 ? 's' : '') + '] LT'; + }, + lastWeek: function () { + return ( + '[el] dddd [pasado a la' + + (this.hours() !== 1 ? 's' : '') + + '] LT' + ); + }, + sameElse: 'L', + }, + relativeTime: { + future: 'en %s', + past: 'hace %s', + s: 'unos segundos', + ss: '%d segundos', + m: 'un minuto', + mm: '%d minutos', + h: 'una hora', + hh: '%d horas', + d: 'un día', + dd: '%d días', + w: 'una semana', + ww: '%d semanas', + M: 'un mes', + MM: '%d meses', + y: 'un año', + yy: '%d años', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + invalidDate: 'Fecha inválida', + }); + + //! moment.js locale configuration + + function processRelativeTime$3(number, withoutSuffix, key, isFuture) { + var format = { + s: ['mõne sekundi', 'mõni sekund', 'paar sekundit'], + ss: [number + 'sekundi', number + 'sekundit'], + m: ['ühe minuti', 'üks minut'], + mm: [number + ' minuti', number + ' minutit'], + h: ['ühe tunni', 'tund aega', 'üks tund'], + hh: [number + ' tunni', number + ' tundi'], + d: ['ühe päeva', 'üks päev'], + M: ['kuu aja', 'kuu aega', 'üks kuu'], + MM: [number + ' kuu', number + ' kuud'], + y: ['ühe aasta', 'aasta', 'üks aasta'], + yy: [number + ' aasta', number + ' aastat'], + }; + if (withoutSuffix) { + return format[key][2] ? format[key][2] : format[key][1]; + } + return isFuture ? format[key][0] : format[key][1]; + } + + hooks.defineLocale('et', { + months: 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split( + '_' + ), + monthsShort: + 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'), + weekdays: + 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split( + '_' + ), + weekdaysShort: 'P_E_T_K_N_R_L'.split('_'), + weekdaysMin: 'P_E_T_K_N_R_L'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm', + LLLL: 'dddd, D. MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[Täna,] LT', + nextDay: '[Homme,] LT', + nextWeek: '[Järgmine] dddd LT', + lastDay: '[Eile,] LT', + lastWeek: '[Eelmine] dddd LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s pärast', + past: '%s tagasi', + s: processRelativeTime$3, + ss: processRelativeTime$3, + m: processRelativeTime$3, + mm: processRelativeTime$3, + h: processRelativeTime$3, + hh: processRelativeTime$3, + d: processRelativeTime$3, + dd: '%d päeva', + M: processRelativeTime$3, + MM: processRelativeTime$3, + y: processRelativeTime$3, + yy: processRelativeTime$3, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('eu', { + months: 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split( + '_' + ), + monthsShort: + 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split( + '_' + ), + monthsParseExact: true, + weekdays: + 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split( + '_' + ), + weekdaysShort: 'ig._al._ar._az._og._ol._lr.'.split('_'), + weekdaysMin: 'ig_al_ar_az_og_ol_lr'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: 'YYYY[ko] MMMM[ren] D[a]', + LLL: 'YYYY[ko] MMMM[ren] D[a] HH:mm', + LLLL: 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm', + l: 'YYYY-M-D', + ll: 'YYYY[ko] MMM D[a]', + lll: 'YYYY[ko] MMM D[a] HH:mm', + llll: 'ddd, YYYY[ko] MMM D[a] HH:mm', + }, + calendar: { + sameDay: '[gaur] LT[etan]', + nextDay: '[bihar] LT[etan]', + nextWeek: 'dddd LT[etan]', + lastDay: '[atzo] LT[etan]', + lastWeek: '[aurreko] dddd LT[etan]', + sameElse: 'L', + }, + relativeTime: { + future: '%s barru', + past: 'duela %s', + s: 'segundo batzuk', + ss: '%d segundo', + m: 'minutu bat', + mm: '%d minutu', + h: 'ordu bat', + hh: '%d ordu', + d: 'egun bat', + dd: '%d egun', + M: 'hilabete bat', + MM: '%d hilabete', + y: 'urte bat', + yy: '%d urte', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$6 = { + 1: '۱', + 2: '۲', + 3: '۳', + 4: '۴', + 5: '۵', + 6: '۶', + 7: '۷', + 8: '۸', + 9: '۹', + 0: '۰', + }, + numberMap$5 = { + '۱': '1', + '۲': '2', + '۳': '3', + '۴': '4', + '۵': '5', + '۶': '6', + '۷': '7', + '۸': '8', + '۹': '9', + '۰': '0', + }; + + hooks.defineLocale('fa', { + months: 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split( + '_' + ), + monthsShort: + 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split( + '_' + ), + weekdays: + 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split( + '_' + ), + weekdaysShort: + 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split( + '_' + ), + weekdaysMin: 'ی_د_س_چ_پ_ج_ش'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + meridiemParse: /قبل از ظهر|بعد از ظهر/, + isPM: function (input) { + return /بعد از ظهر/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'قبل از ظهر'; + } else { + return 'بعد از ظهر'; + } + }, + calendar: { + sameDay: '[امروز ساعت] LT', + nextDay: '[فردا ساعت] LT', + nextWeek: 'dddd [ساعت] LT', + lastDay: '[دیروز ساعت] LT', + lastWeek: 'dddd [پیش] [ساعت] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'در %s', + past: '%s پیش', + s: 'چند ثانیه', + ss: '%d ثانیه', + m: 'یک دقیقه', + mm: '%d دقیقه', + h: 'یک ساعت', + hh: '%d ساعت', + d: 'یک روز', + dd: '%d روز', + M: 'یک ماه', + MM: '%d ماه', + y: 'یک سال', + yy: '%d سال', + }, + preparse: function (string) { + return string + .replace(/[۰-۹]/g, function (match) { + return numberMap$5[match]; + }) + .replace(/،/g, ','); + }, + postformat: function (string) { + return string + .replace(/\d/g, function (match) { + return symbolMap$6[match]; + }) + .replace(/,/g, '،'); + }, + dayOfMonthOrdinalParse: /\d{1,2}م/, + ordinal: '%dم', + week: { + dow: 6, // Saturday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var numbersPast = + 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split( + ' ' + ), + numbersFuture = [ + 'nolla', + 'yhden', + 'kahden', + 'kolmen', + 'neljän', + 'viiden', + 'kuuden', + numbersPast[7], + numbersPast[8], + numbersPast[9], + ]; + function translate$2(number, withoutSuffix, key, isFuture) { + var result = ''; + switch (key) { + case 's': + return isFuture ? 'muutaman sekunnin' : 'muutama sekunti'; + case 'ss': + result = isFuture ? 'sekunnin' : 'sekuntia'; + break; + case 'm': + return isFuture ? 'minuutin' : 'minuutti'; + case 'mm': + result = isFuture ? 'minuutin' : 'minuuttia'; + break; + case 'h': + return isFuture ? 'tunnin' : 'tunti'; + case 'hh': + result = isFuture ? 'tunnin' : 'tuntia'; + break; + case 'd': + return isFuture ? 'päivän' : 'päivä'; + case 'dd': + result = isFuture ? 'päivän' : 'päivää'; + break; + case 'M': + return isFuture ? 'kuukauden' : 'kuukausi'; + case 'MM': + result = isFuture ? 'kuukauden' : 'kuukautta'; + break; + case 'y': + return isFuture ? 'vuoden' : 'vuosi'; + case 'yy': + result = isFuture ? 'vuoden' : 'vuotta'; + break; + } + result = verbalNumber(number, isFuture) + ' ' + result; + return result; + } + function verbalNumber(number, isFuture) { + return number < 10 + ? isFuture + ? numbersFuture[number] + : numbersPast[number] + : number; + } + + hooks.defineLocale('fi', { + months: 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split( + '_' + ), + monthsShort: + 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split( + '_' + ), + weekdays: + 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split( + '_' + ), + weekdaysShort: 'su_ma_ti_ke_to_pe_la'.split('_'), + weekdaysMin: 'su_ma_ti_ke_to_pe_la'.split('_'), + longDateFormat: { + LT: 'HH.mm', + LTS: 'HH.mm.ss', + L: 'DD.MM.YYYY', + LL: 'Do MMMM[ta] YYYY', + LLL: 'Do MMMM[ta] YYYY, [klo] HH.mm', + LLLL: 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm', + l: 'D.M.YYYY', + ll: 'Do MMM YYYY', + lll: 'Do MMM YYYY, [klo] HH.mm', + llll: 'ddd, Do MMM YYYY, [klo] HH.mm', + }, + calendar: { + sameDay: '[tänään] [klo] LT', + nextDay: '[huomenna] [klo] LT', + nextWeek: 'dddd [klo] LT', + lastDay: '[eilen] [klo] LT', + lastWeek: '[viime] dddd[na] [klo] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s päästä', + past: '%s sitten', + s: translate$2, + ss: translate$2, + m: translate$2, + mm: translate$2, + h: translate$2, + hh: translate$2, + d: translate$2, + dd: translate$2, + M: translate$2, + MM: translate$2, + y: translate$2, + yy: translate$2, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('fil', { + months: 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split( + '_' + ), + monthsShort: 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'), + weekdays: 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split( + '_' + ), + weekdaysShort: 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'), + weekdaysMin: 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'MM/D/YYYY', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY HH:mm', + LLLL: 'dddd, MMMM DD, YYYY HH:mm', + }, + calendar: { + sameDay: 'LT [ngayong araw]', + nextDay: '[Bukas ng] LT', + nextWeek: 'LT [sa susunod na] dddd', + lastDay: 'LT [kahapon]', + lastWeek: 'LT [noong nakaraang] dddd', + sameElse: 'L', + }, + relativeTime: { + future: 'sa loob ng %s', + past: '%s ang nakalipas', + s: 'ilang segundo', + ss: '%d segundo', + m: 'isang minuto', + mm: '%d minuto', + h: 'isang oras', + hh: '%d oras', + d: 'isang araw', + dd: '%d araw', + M: 'isang buwan', + MM: '%d buwan', + y: 'isang taon', + yy: '%d taon', + }, + dayOfMonthOrdinalParse: /\d{1,2}/, + ordinal: function (number) { + return number; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('fo', { + months: 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split( + '_' + ), + monthsShort: 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), + weekdays: + 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split( + '_' + ), + weekdaysShort: 'sun_mán_týs_mik_hós_frí_ley'.split('_'), + weekdaysMin: 'su_má_tý_mi_hó_fr_le'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D. MMMM, YYYY HH:mm', + }, + calendar: { + sameDay: '[Í dag kl.] LT', + nextDay: '[Í morgin kl.] LT', + nextWeek: 'dddd [kl.] LT', + lastDay: '[Í gjár kl.] LT', + lastWeek: '[síðstu] dddd [kl] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'um %s', + past: '%s síðani', + s: 'fá sekund', + ss: '%d sekundir', + m: 'ein minuttur', + mm: '%d minuttir', + h: 'ein tími', + hh: '%d tímar', + d: 'ein dagur', + dd: '%d dagar', + M: 'ein mánaður', + MM: '%d mánaðir', + y: 'eitt ár', + yy: '%d ár', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('fr-ca', { + months: 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split( + '_' + ), + monthsShort: + 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), + weekdaysShort: 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), + weekdaysMin: 'di_lu_ma_me_je_ve_sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Aujourd’hui à] LT', + nextDay: '[Demain à] LT', + nextWeek: 'dddd [à] LT', + lastDay: '[Hier à] LT', + lastWeek: 'dddd [dernier à] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dans %s', + past: 'il y a %s', + s: 'quelques secondes', + ss: '%d secondes', + m: 'une minute', + mm: '%d minutes', + h: 'une heure', + hh: '%d heures', + d: 'un jour', + dd: '%d jours', + M: 'un mois', + MM: '%d mois', + y: 'un an', + yy: '%d ans', + }, + dayOfMonthOrdinalParse: /\d{1,2}(er|e)/, + ordinal: function (number, period) { + switch (period) { + // Words with masculine grammatical gender: mois, trimestre, jour + default: + case 'M': + case 'Q': + case 'D': + case 'DDD': + case 'd': + return number + (number === 1 ? 'er' : 'e'); + + // Words with feminine grammatical gender: semaine + case 'w': + case 'W': + return number + (number === 1 ? 're' : 'e'); + } + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('fr-ch', { + months: 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split( + '_' + ), + monthsShort: + 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), + weekdaysShort: 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), + weekdaysMin: 'di_lu_ma_me_je_ve_sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Aujourd’hui à] LT', + nextDay: '[Demain à] LT', + nextWeek: 'dddd [à] LT', + lastDay: '[Hier à] LT', + lastWeek: 'dddd [dernier à] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dans %s', + past: 'il y a %s', + s: 'quelques secondes', + ss: '%d secondes', + m: 'une minute', + mm: '%d minutes', + h: 'une heure', + hh: '%d heures', + d: 'un jour', + dd: '%d jours', + M: 'un mois', + MM: '%d mois', + y: 'un an', + yy: '%d ans', + }, + dayOfMonthOrdinalParse: /\d{1,2}(er|e)/, + ordinal: function (number, period) { + switch (period) { + // Words with masculine grammatical gender: mois, trimestre, jour + default: + case 'M': + case 'Q': + case 'D': + case 'DDD': + case 'd': + return number + (number === 1 ? 'er' : 'e'); + + // Words with feminine grammatical gender: semaine + case 'w': + case 'W': + return number + (number === 1 ? 're' : 'e'); + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsStrictRegex$1 = + /^(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i, + monthsShortStrictRegex$1 = + /(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?)/i, + monthsRegex$7 = + /(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?|janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i, + monthsParse$6 = [ + /^janv/i, + /^févr/i, + /^mars/i, + /^avr/i, + /^mai/i, + /^juin/i, + /^juil/i, + /^août/i, + /^sept/i, + /^oct/i, + /^nov/i, + /^déc/i, + ]; + + hooks.defineLocale('fr', { + months: 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split( + '_' + ), + monthsShort: + 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split( + '_' + ), + monthsRegex: monthsRegex$7, + monthsShortRegex: monthsRegex$7, + monthsStrictRegex: monthsStrictRegex$1, + monthsShortStrictRegex: monthsShortStrictRegex$1, + monthsParse: monthsParse$6, + longMonthsParse: monthsParse$6, + shortMonthsParse: monthsParse$6, + weekdays: 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), + weekdaysShort: 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), + weekdaysMin: 'di_lu_ma_me_je_ve_sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Aujourd’hui à] LT', + nextDay: '[Demain à] LT', + nextWeek: 'dddd [à] LT', + lastDay: '[Hier à] LT', + lastWeek: 'dddd [dernier à] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dans %s', + past: 'il y a %s', + s: 'quelques secondes', + ss: '%d secondes', + m: 'une minute', + mm: '%d minutes', + h: 'une heure', + hh: '%d heures', + d: 'un jour', + dd: '%d jours', + w: 'une semaine', + ww: '%d semaines', + M: 'un mois', + MM: '%d mois', + y: 'un an', + yy: '%d ans', + }, + dayOfMonthOrdinalParse: /\d{1,2}(er|)/, + ordinal: function (number, period) { + switch (period) { + // TODO: Return 'e' when day of month > 1. Move this case inside + // block for masculine words below. + // See https://github.com/moment/moment/issues/3375 + case 'D': + return number + (number === 1 ? 'er' : ''); + + // Words with masculine grammatical gender: mois, trimestre, jour + default: + case 'M': + case 'Q': + case 'DDD': + case 'd': + return number + (number === 1 ? 'er' : 'e'); + + // Words with feminine grammatical gender: semaine + case 'w': + case 'W': + return number + (number === 1 ? 're' : 'e'); + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsShortWithDots = + 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_'), + monthsShortWithoutDots = + 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'); + + hooks.defineLocale('fy', { + months: 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortWithDots; + } else if (/-MMM-/.test(format)) { + return monthsShortWithoutDots[m.month()]; + } else { + return monthsShortWithDots[m.month()]; + } + }, + monthsParseExact: true, + weekdays: 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split( + '_' + ), + weekdaysShort: 'si._mo._ti._wo._to._fr._so.'.split('_'), + weekdaysMin: 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD-MM-YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[hjoed om] LT', + nextDay: '[moarn om] LT', + nextWeek: 'dddd [om] LT', + lastDay: '[juster om] LT', + lastWeek: '[ôfrûne] dddd [om] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'oer %s', + past: '%s lyn', + s: 'in pear sekonden', + ss: '%d sekonden', + m: 'ien minút', + mm: '%d minuten', + h: 'ien oere', + hh: '%d oeren', + d: 'ien dei', + dd: '%d dagen', + M: 'ien moanne', + MM: '%d moannen', + y: 'ien jier', + yy: '%d jierren', + }, + dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/, + ordinal: function (number) { + return ( + number + + (number === 1 || number === 8 || number >= 20 ? 'ste' : 'de') + ); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var months$6 = [ + 'Eanáir', + 'Feabhra', + 'Márta', + 'Aibreán', + 'Bealtaine', + 'Meitheamh', + 'Iúil', + 'Lúnasa', + 'Meán Fómhair', + 'Deireadh Fómhair', + 'Samhain', + 'Nollaig', + ], + monthsShort$5 = [ + 'Ean', + 'Feabh', + 'Márt', + 'Aib', + 'Beal', + 'Meith', + 'Iúil', + 'Lún', + 'M.F.', + 'D.F.', + 'Samh', + 'Noll', + ], + weekdays$1 = [ + 'Dé Domhnaigh', + 'Dé Luain', + 'Dé Máirt', + 'Dé Céadaoin', + 'Déardaoin', + 'Dé hAoine', + 'Dé Sathairn', + ], + weekdaysShort = ['Domh', 'Luan', 'Máirt', 'Céad', 'Déar', 'Aoine', 'Sath'], + weekdaysMin = ['Do', 'Lu', 'Má', 'Cé', 'Dé', 'A', 'Sa']; + + hooks.defineLocale('ga', { + months: months$6, + monthsShort: monthsShort$5, + monthsParseExact: true, + weekdays: weekdays$1, + weekdaysShort: weekdaysShort, + weekdaysMin: weekdaysMin, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Inniu ag] LT', + nextDay: '[Amárach ag] LT', + nextWeek: 'dddd [ag] LT', + lastDay: '[Inné ag] LT', + lastWeek: 'dddd [seo caite] [ag] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'i %s', + past: '%s ó shin', + s: 'cúpla soicind', + ss: '%d soicind', + m: 'nóiméad', + mm: '%d nóiméad', + h: 'uair an chloig', + hh: '%d uair an chloig', + d: 'lá', + dd: '%d lá', + M: 'mí', + MM: '%d míonna', + y: 'bliain', + yy: '%d bliain', + }, + dayOfMonthOrdinalParse: /\d{1,2}(d|na|mh)/, + ordinal: function (number) { + var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var months$7 = [ + 'Am Faoilleach', + 'An Gearran', + 'Am Màrt', + 'An Giblean', + 'An Cèitean', + 'An t-Ògmhios', + 'An t-Iuchar', + 'An Lùnastal', + 'An t-Sultain', + 'An Dàmhair', + 'An t-Samhain', + 'An Dùbhlachd', + ], + monthsShort$6 = [ + 'Faoi', + 'Gear', + 'Màrt', + 'Gibl', + 'Cèit', + 'Ògmh', + 'Iuch', + 'Lùn', + 'Sult', + 'Dàmh', + 'Samh', + 'Dùbh', + ], + weekdays$2 = [ + 'Didòmhnaich', + 'Diluain', + 'Dimàirt', + 'Diciadain', + 'Diardaoin', + 'Dihaoine', + 'Disathairne', + ], + weekdaysShort$1 = ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'], + weekdaysMin$1 = ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa']; + + hooks.defineLocale('gd', { + months: months$7, + monthsShort: monthsShort$6, + monthsParseExact: true, + weekdays: weekdays$2, + weekdaysShort: weekdaysShort$1, + weekdaysMin: weekdaysMin$1, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[An-diugh aig] LT', + nextDay: '[A-màireach aig] LT', + nextWeek: 'dddd [aig] LT', + lastDay: '[An-dè aig] LT', + lastWeek: 'dddd [seo chaidh] [aig] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'ann an %s', + past: 'bho chionn %s', + s: 'beagan diogan', + ss: '%d diogan', + m: 'mionaid', + mm: '%d mionaidean', + h: 'uair', + hh: '%d uairean', + d: 'latha', + dd: '%d latha', + M: 'mìos', + MM: '%d mìosan', + y: 'bliadhna', + yy: '%d bliadhna', + }, + dayOfMonthOrdinalParse: /\d{1,2}(d|na|mh)/, + ordinal: function (number) { + var output = number === 1 ? 'd' : number % 10 === 2 ? 'na' : 'mh'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('gl', { + months: 'xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro'.split( + '_' + ), + monthsShort: + 'xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'domingo_luns_martes_mércores_xoves_venres_sábado'.split('_'), + weekdaysShort: 'dom._lun._mar._mér._xov._ven._sáb.'.split('_'), + weekdaysMin: 'do_lu_ma_mé_xo_ve_sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY H:mm', + LLLL: 'dddd, D [de] MMMM [de] YYYY H:mm', + }, + calendar: { + sameDay: function () { + return '[hoxe ' + (this.hours() !== 1 ? 'ás' : 'á') + '] LT'; + }, + nextDay: function () { + return '[mañá ' + (this.hours() !== 1 ? 'ás' : 'á') + '] LT'; + }, + nextWeek: function () { + return 'dddd [' + (this.hours() !== 1 ? 'ás' : 'a') + '] LT'; + }, + lastDay: function () { + return '[onte ' + (this.hours() !== 1 ? 'á' : 'a') + '] LT'; + }, + lastWeek: function () { + return ( + '[o] dddd [pasado ' + (this.hours() !== 1 ? 'ás' : 'a') + '] LT' + ); + }, + sameElse: 'L', + }, + relativeTime: { + future: function (str) { + if (str.indexOf('un') === 0) { + return 'n' + str; + } + return 'en ' + str; + }, + past: 'hai %s', + s: 'uns segundos', + ss: '%d segundos', + m: 'un minuto', + mm: '%d minutos', + h: 'unha hora', + hh: '%d horas', + d: 'un día', + dd: '%d días', + M: 'un mes', + MM: '%d meses', + y: 'un ano', + yy: '%d anos', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function processRelativeTime$4(number, withoutSuffix, key, isFuture) { + var format = { + s: ['थोडया सॅकंडांनी', 'थोडे सॅकंड'], + ss: [number + ' सॅकंडांनी', number + ' सॅकंड'], + m: ['एका मिणटान', 'एक मिनूट'], + mm: [number + ' मिणटांनी', number + ' मिणटां'], + h: ['एका वरान', 'एक वर'], + hh: [number + ' वरांनी', number + ' वरां'], + d: ['एका दिसान', 'एक दीस'], + dd: [number + ' दिसांनी', number + ' दीस'], + M: ['एका म्हयन्यान', 'एक म्हयनो'], + MM: [number + ' म्हयन्यानी', number + ' म्हयने'], + y: ['एका वर्सान', 'एक वर्स'], + yy: [number + ' वर्सांनी', number + ' वर्सां'], + }; + return isFuture ? format[key][0] : format[key][1]; + } + + hooks.defineLocale('gom-deva', { + months: { + standalone: + 'जानेवारी_फेब्रुवारी_मार्च_एप्रील_मे_जून_जुलय_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split( + '_' + ), + format: 'जानेवारीच्या_फेब्रुवारीच्या_मार्चाच्या_एप्रीलाच्या_मेयाच्या_जूनाच्या_जुलयाच्या_ऑगस्टाच्या_सप्टेंबराच्या_ऑक्टोबराच्या_नोव्हेंबराच्या_डिसेंबराच्या'.split( + '_' + ), + isFormat: /MMMM(\s)+D[oD]?/, + }, + monthsShort: + 'जाने._फेब्रु._मार्च_एप्री._मे_जून_जुल._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'आयतार_सोमार_मंगळार_बुधवार_बिरेस्तार_सुक्रार_शेनवार'.split('_'), + weekdaysShort: 'आयत._सोम._मंगळ._बुध._ब्रेस्त._सुक्र._शेन.'.split('_'), + weekdaysMin: 'आ_सो_मं_बु_ब्रे_सु_शे'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'A h:mm [वाजतां]', + LTS: 'A h:mm:ss [वाजतां]', + L: 'DD-MM-YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY A h:mm [वाजतां]', + LLLL: 'dddd, MMMM Do, YYYY, A h:mm [वाजतां]', + llll: 'ddd, D MMM YYYY, A h:mm [वाजतां]', + }, + calendar: { + sameDay: '[आयज] LT', + nextDay: '[फाल्यां] LT', + nextWeek: '[फुडलो] dddd[,] LT', + lastDay: '[काल] LT', + lastWeek: '[फाटलो] dddd[,] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s', + past: '%s आदीं', + s: processRelativeTime$4, + ss: processRelativeTime$4, + m: processRelativeTime$4, + mm: processRelativeTime$4, + h: processRelativeTime$4, + hh: processRelativeTime$4, + d: processRelativeTime$4, + dd: processRelativeTime$4, + M: processRelativeTime$4, + MM: processRelativeTime$4, + y: processRelativeTime$4, + yy: processRelativeTime$4, + }, + dayOfMonthOrdinalParse: /\d{1,2}(वेर)/, + ordinal: function (number, period) { + switch (period) { + // the ordinal 'वेर' only applies to day of the month + case 'D': + return number + 'वेर'; + default: + case 'M': + case 'Q': + case 'DDD': + case 'd': + case 'w': + case 'W': + return number; + } + }, + week: { + dow: 0, // Sunday is the first day of the week + doy: 3, // The week that contains Jan 4th is the first week of the year (7 + 0 - 4) + }, + meridiemParse: /राती|सकाळीं|दनपारां|सांजे/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'राती') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'सकाळीं') { + return hour; + } else if (meridiem === 'दनपारां') { + return hour > 12 ? hour : hour + 12; + } else if (meridiem === 'सांजे') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'राती'; + } else if (hour < 12) { + return 'सकाळीं'; + } else if (hour < 16) { + return 'दनपारां'; + } else if (hour < 20) { + return 'सांजे'; + } else { + return 'राती'; + } + }, + }); + + //! moment.js locale configuration + + function processRelativeTime$5(number, withoutSuffix, key, isFuture) { + var format = { + s: ['thoddea sekondamni', 'thodde sekond'], + ss: [number + ' sekondamni', number + ' sekond'], + m: ['eka mintan', 'ek minut'], + mm: [number + ' mintamni', number + ' mintam'], + h: ['eka voran', 'ek vor'], + hh: [number + ' voramni', number + ' voram'], + d: ['eka disan', 'ek dis'], + dd: [number + ' disamni', number + ' dis'], + M: ['eka mhoinean', 'ek mhoino'], + MM: [number + ' mhoineamni', number + ' mhoine'], + y: ['eka vorsan', 'ek voros'], + yy: [number + ' vorsamni', number + ' vorsam'], + }; + return isFuture ? format[key][0] : format[key][1]; + } + + hooks.defineLocale('gom-latn', { + months: { + standalone: + 'Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr'.split( + '_' + ), + format: 'Janerachea_Febrerachea_Marsachea_Abrilachea_Maiachea_Junachea_Julaiachea_Agostachea_Setembrachea_Otubrachea_Novembrachea_Dezembrachea'.split( + '_' + ), + isFormat: /MMMM(\s)+D[oD]?/, + }, + monthsShort: + 'Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.'.split('_'), + monthsParseExact: true, + weekdays: "Aitar_Somar_Mongllar_Budhvar_Birestar_Sukrar_Son'var".split('_'), + weekdaysShort: 'Ait._Som._Mon._Bud._Bre._Suk._Son.'.split('_'), + weekdaysMin: 'Ai_Sm_Mo_Bu_Br_Su_Sn'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'A h:mm [vazta]', + LTS: 'A h:mm:ss [vazta]', + L: 'DD-MM-YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY A h:mm [vazta]', + LLLL: 'dddd, MMMM Do, YYYY, A h:mm [vazta]', + llll: 'ddd, D MMM YYYY, A h:mm [vazta]', + }, + calendar: { + sameDay: '[Aiz] LT', + nextDay: '[Faleam] LT', + nextWeek: '[Fuddlo] dddd[,] LT', + lastDay: '[Kal] LT', + lastWeek: '[Fattlo] dddd[,] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s', + past: '%s adim', + s: processRelativeTime$5, + ss: processRelativeTime$5, + m: processRelativeTime$5, + mm: processRelativeTime$5, + h: processRelativeTime$5, + hh: processRelativeTime$5, + d: processRelativeTime$5, + dd: processRelativeTime$5, + M: processRelativeTime$5, + MM: processRelativeTime$5, + y: processRelativeTime$5, + yy: processRelativeTime$5, + }, + dayOfMonthOrdinalParse: /\d{1,2}(er)/, + ordinal: function (number, period) { + switch (period) { + // the ordinal 'er' only applies to day of the month + case 'D': + return number + 'er'; + default: + case 'M': + case 'Q': + case 'DDD': + case 'd': + case 'w': + case 'W': + return number; + } + }, + week: { + dow: 0, // Sunday is the first day of the week + doy: 3, // The week that contains Jan 4th is the first week of the year (7 + 0 - 4) + }, + meridiemParse: /rati|sokallim|donparam|sanje/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'rati') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'sokallim') { + return hour; + } else if (meridiem === 'donparam') { + return hour > 12 ? hour : hour + 12; + } else if (meridiem === 'sanje') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'rati'; + } else if (hour < 12) { + return 'sokallim'; + } else if (hour < 16) { + return 'donparam'; + } else if (hour < 20) { + return 'sanje'; + } else { + return 'rati'; + } + }, + }); + + //! moment.js locale configuration + + var symbolMap$7 = { + 1: '૧', + 2: '૨', + 3: '૩', + 4: '૪', + 5: '૫', + 6: '૬', + 7: '૭', + 8: '૮', + 9: '૯', + 0: '૦', + }, + numberMap$6 = { + '૧': '1', + '૨': '2', + '૩': '3', + '૪': '4', + '૫': '5', + '૬': '6', + '૭': '7', + '૮': '8', + '૯': '9', + '૦': '0', + }; + + hooks.defineLocale('gu', { + months: 'જાન્યુઆરી_ફેબ્રુઆરી_માર્ચ_એપ્રિલ_મે_જૂન_જુલાઈ_ઑગસ્ટ_સપ્ટેમ્બર_ઑક્ટ્બર_નવેમ્બર_ડિસેમ્બર'.split( + '_' + ), + monthsShort: + 'જાન્યુ._ફેબ્રુ._માર્ચ_એપ્રિ._મે_જૂન_જુલા._ઑગ._સપ્ટે._ઑક્ટ્._નવે._ડિસે.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'રવિવાર_સોમવાર_મંગળવાર_બુધ્વાર_ગુરુવાર_શુક્રવાર_શનિવાર'.split( + '_' + ), + weekdaysShort: 'રવિ_સોમ_મંગળ_બુધ્_ગુરુ_શુક્ર_શનિ'.split('_'), + weekdaysMin: 'ર_સો_મં_બુ_ગુ_શુ_શ'.split('_'), + longDateFormat: { + LT: 'A h:mm વાગ્યે', + LTS: 'A h:mm:ss વાગ્યે', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm વાગ્યે', + LLLL: 'dddd, D MMMM YYYY, A h:mm વાગ્યે', + }, + calendar: { + sameDay: '[આજ] LT', + nextDay: '[કાલે] LT', + nextWeek: 'dddd, LT', + lastDay: '[ગઇકાલે] LT', + lastWeek: '[પાછલા] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s મા', + past: '%s પહેલા', + s: 'અમુક પળો', + ss: '%d સેકંડ', + m: 'એક મિનિટ', + mm: '%d મિનિટ', + h: 'એક કલાક', + hh: '%d કલાક', + d: 'એક દિવસ', + dd: '%d દિવસ', + M: 'એક મહિનો', + MM: '%d મહિનો', + y: 'એક વર્ષ', + yy: '%d વર્ષ', + }, + preparse: function (string) { + return string.replace(/[૧૨૩૪૫૬૭૮૯૦]/g, function (match) { + return numberMap$6[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$7[match]; + }); + }, + // Gujarati notation for meridiems are quite fuzzy in practice. While there exists + // a rigid notion of a 'Pahar' it is not used as rigidly in modern Gujarati. + meridiemParse: /રાત|બપોર|સવાર|સાંજ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'રાત') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'સવાર') { + return hour; + } else if (meridiem === 'બપોર') { + return hour >= 10 ? hour : hour + 12; + } else if (meridiem === 'સાંજ') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'રાત'; + } else if (hour < 10) { + return 'સવાર'; + } else if (hour < 17) { + return 'બપોર'; + } else if (hour < 20) { + return 'સાંજ'; + } else { + return 'રાત'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('he', { + months: 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split( + '_' + ), + monthsShort: + 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'), + weekdays: 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'), + weekdaysShort: 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'), + weekdaysMin: 'א_ב_ג_ד_ה_ו_ש'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [ב]MMMM YYYY', + LLL: 'D [ב]MMMM YYYY HH:mm', + LLLL: 'dddd, D [ב]MMMM YYYY HH:mm', + l: 'D/M/YYYY', + ll: 'D MMM YYYY', + lll: 'D MMM YYYY HH:mm', + llll: 'ddd, D MMM YYYY HH:mm', + }, + calendar: { + sameDay: '[היום ב־]LT', + nextDay: '[מחר ב־]LT', + nextWeek: 'dddd [בשעה] LT', + lastDay: '[אתמול ב־]LT', + lastWeek: '[ביום] dddd [האחרון בשעה] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'בעוד %s', + past: 'לפני %s', + s: 'מספר שניות', + ss: '%d שניות', + m: 'דקה', + mm: '%d דקות', + h: 'שעה', + hh: function (number) { + if (number === 2) { + return 'שעתיים'; + } + return number + ' שעות'; + }, + d: 'יום', + dd: function (number) { + if (number === 2) { + return 'יומיים'; + } + return number + ' ימים'; + }, + M: 'חודש', + MM: function (number) { + if (number === 2) { + return 'חודשיים'; + } + return number + ' חודשים'; + }, + y: 'שנה', + yy: function (number) { + if (number === 2) { + return 'שנתיים'; + } else if (number % 10 === 0 && number !== 10) { + return number + ' שנה'; + } + return number + ' שנים'; + }, + }, + meridiemParse: + /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i, + isPM: function (input) { + return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 5) { + return 'לפנות בוקר'; + } else if (hour < 10) { + return 'בבוקר'; + } else if (hour < 12) { + return isLower ? 'לפנה"צ' : 'לפני הצהריים'; + } else if (hour < 18) { + return isLower ? 'אחה"צ' : 'אחרי הצהריים'; + } else { + return 'בערב'; + } + }, + }); + + //! moment.js locale configuration + + var symbolMap$8 = { + 1: '१', + 2: '२', + 3: '३', + 4: '४', + 5: '५', + 6: '६', + 7: '७', + 8: '८', + 9: '९', + 0: '०', + }, + numberMap$7 = { + '१': '1', + '२': '2', + '३': '3', + '४': '4', + '५': '5', + '६': '6', + '७': '7', + '८': '8', + '९': '9', + '०': '0', + }, + monthsParse$7 = [ + /^जन/i, + /^फ़र|फर/i, + /^मार्च/i, + /^अप्रै/i, + /^मई/i, + /^जून/i, + /^जुल/i, + /^अग/i, + /^सितं|सित/i, + /^अक्टू/i, + /^नव|नवं/i, + /^दिसं|दिस/i, + ], + shortMonthsParse = [ + /^जन/i, + /^फ़र/i, + /^मार्च/i, + /^अप्रै/i, + /^मई/i, + /^जून/i, + /^जुल/i, + /^अग/i, + /^सित/i, + /^अक्टू/i, + /^नव/i, + /^दिस/i, + ]; + + hooks.defineLocale('hi', { + months: { + format: 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split( + '_' + ), + standalone: + 'जनवरी_फरवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितंबर_अक्टूबर_नवंबर_दिसंबर'.split( + '_' + ), + }, + monthsShort: + 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'), + weekdays: 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'), + weekdaysShort: 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'), + weekdaysMin: 'र_सो_मं_बु_गु_शु_श'.split('_'), + longDateFormat: { + LT: 'A h:mm बजे', + LTS: 'A h:mm:ss बजे', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm बजे', + LLLL: 'dddd, D MMMM YYYY, A h:mm बजे', + }, + + monthsParse: monthsParse$7, + longMonthsParse: monthsParse$7, + shortMonthsParse: shortMonthsParse, + + monthsRegex: + /^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i, + + monthsShortRegex: + /^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i, + + monthsStrictRegex: + /^(जनवरी?|फ़रवरी|फरवरी?|मार्च?|अप्रैल?|मई?|जून?|जुलाई?|अगस्त?|सितम्बर|सितंबर|सित?\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर?|दिसम्बर|दिसंबर?)/i, + + monthsShortStrictRegex: + /^(जन\.?|फ़र\.?|मार्च?|अप्रै\.?|मई?|जून?|जुल\.?|अग\.?|सित\.?|अक्टू\.?|नव\.?|दिस\.?)/i, + + calendar: { + sameDay: '[आज] LT', + nextDay: '[कल] LT', + nextWeek: 'dddd, LT', + lastDay: '[कल] LT', + lastWeek: '[पिछले] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s में', + past: '%s पहले', + s: 'कुछ ही क्षण', + ss: '%d सेकंड', + m: 'एक मिनट', + mm: '%d मिनट', + h: 'एक घंटा', + hh: '%d घंटे', + d: 'एक दिन', + dd: '%d दिन', + M: 'एक महीने', + MM: '%d महीने', + y: 'एक वर्ष', + yy: '%d वर्ष', + }, + preparse: function (string) { + return string.replace(/[१२३४५६७८९०]/g, function (match) { + return numberMap$7[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$8[match]; + }); + }, + // Hindi notation for meridiems are quite fuzzy in practice. While there exists + // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi. + meridiemParse: /रात|सुबह|दोपहर|शाम/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'रात') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'सुबह') { + return hour; + } else if (meridiem === 'दोपहर') { + return hour >= 10 ? hour : hour + 12; + } else if (meridiem === 'शाम') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'रात'; + } else if (hour < 10) { + return 'सुबह'; + } else if (hour < 17) { + return 'दोपहर'; + } else if (hour < 20) { + return 'शाम'; + } else { + return 'रात'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function translate$3(number, withoutSuffix, key) { + var result = number + ' '; + switch (key) { + case 'ss': + if (number === 1) { + result += 'sekunda'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'sekunde'; + } else { + result += 'sekundi'; + } + return result; + case 'm': + return withoutSuffix ? 'jedna minuta' : 'jedne minute'; + case 'mm': + if (number === 1) { + result += 'minuta'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'minute'; + } else { + result += 'minuta'; + } + return result; + case 'h': + return withoutSuffix ? 'jedan sat' : 'jednog sata'; + case 'hh': + if (number === 1) { + result += 'sat'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'sata'; + } else { + result += 'sati'; + } + return result; + case 'dd': + if (number === 1) { + result += 'dan'; + } else { + result += 'dana'; + } + return result; + case 'MM': + if (number === 1) { + result += 'mjesec'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'mjeseca'; + } else { + result += 'mjeseci'; + } + return result; + case 'yy': + if (number === 1) { + result += 'godina'; + } else if (number === 2 || number === 3 || number === 4) { + result += 'godine'; + } else { + result += 'godina'; + } + return result; + } + } + + hooks.defineLocale('hr', { + months: { + format: 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split( + '_' + ), + standalone: + 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split( + '_' + ), + }, + monthsShort: + 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split( + '_' + ), + weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), + weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'Do MMMM YYYY', + LLL: 'Do MMMM YYYY H:mm', + LLLL: 'dddd, Do MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[danas u] LT', + nextDay: '[sutra u] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[u] [nedjelju] [u] LT'; + case 3: + return '[u] [srijedu] [u] LT'; + case 6: + return '[u] [subotu] [u] LT'; + case 1: + case 2: + case 4: + case 5: + return '[u] dddd [u] LT'; + } + }, + lastDay: '[jučer u] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[prošlu] [nedjelju] [u] LT'; + case 3: + return '[prošlu] [srijedu] [u] LT'; + case 6: + return '[prošle] [subote] [u] LT'; + case 1: + case 2: + case 4: + case 5: + return '[prošli] dddd [u] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: 'prije %s', + s: 'par sekundi', + ss: translate$3, + m: translate$3, + mm: translate$3, + h: translate$3, + hh: translate$3, + d: 'dan', + dd: translate$3, + M: 'mjesec', + MM: translate$3, + y: 'godinu', + yy: translate$3, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var weekEndings = + 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' '); + function translate$4(number, withoutSuffix, key, isFuture) { + var num = number; + switch (key) { + case 's': + return isFuture || withoutSuffix + ? 'néhány másodperc' + : 'néhány másodperce'; + case 'ss': + return num + (isFuture || withoutSuffix) + ? ' másodperc' + : ' másodperce'; + case 'm': + return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce'); + case 'mm': + return num + (isFuture || withoutSuffix ? ' perc' : ' perce'); + case 'h': + return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája'); + case 'hh': + return num + (isFuture || withoutSuffix ? ' óra' : ' órája'); + case 'd': + return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja'); + case 'dd': + return num + (isFuture || withoutSuffix ? ' nap' : ' napja'); + case 'M': + return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja'); + case 'MM': + return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja'); + case 'y': + return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve'); + case 'yy': + return num + (isFuture || withoutSuffix ? ' év' : ' éve'); + } + return ''; + } + function week(isFuture) { + return ( + (isFuture ? '' : '[múlt] ') + + '[' + + weekEndings[this.day()] + + '] LT[-kor]' + ); + } + + hooks.defineLocale('hu', { + months: 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split( + '_' + ), + monthsShort: + 'jan._feb._márc._ápr._máj._jún._júl._aug._szept._okt._nov._dec.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'), + weekdaysShort: 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'), + weekdaysMin: 'v_h_k_sze_cs_p_szo'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'YYYY.MM.DD.', + LL: 'YYYY. MMMM D.', + LLL: 'YYYY. MMMM D. H:mm', + LLLL: 'YYYY. MMMM D., dddd H:mm', + }, + meridiemParse: /de|du/i, + isPM: function (input) { + return input.charAt(1).toLowerCase() === 'u'; + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 12) { + return isLower === true ? 'de' : 'DE'; + } else { + return isLower === true ? 'du' : 'DU'; + } + }, + calendar: { + sameDay: '[ma] LT[-kor]', + nextDay: '[holnap] LT[-kor]', + nextWeek: function () { + return week.call(this, true); + }, + lastDay: '[tegnap] LT[-kor]', + lastWeek: function () { + return week.call(this, false); + }, + sameElse: 'L', + }, + relativeTime: { + future: '%s múlva', + past: '%s', + s: translate$4, + ss: translate$4, + m: translate$4, + mm: translate$4, + h: translate$4, + hh: translate$4, + d: translate$4, + dd: translate$4, + M: translate$4, + MM: translate$4, + y: translate$4, + yy: translate$4, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('hy-am', { + months: { + format: 'հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի'.split( + '_' + ), + standalone: + 'հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր'.split( + '_' + ), + }, + monthsShort: 'հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ'.split('_'), + weekdays: + 'կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ'.split( + '_' + ), + weekdaysShort: 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'), + weekdaysMin: 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY թ.', + LLL: 'D MMMM YYYY թ., HH:mm', + LLLL: 'dddd, D MMMM YYYY թ., HH:mm', + }, + calendar: { + sameDay: '[այսօր] LT', + nextDay: '[վաղը] LT', + lastDay: '[երեկ] LT', + nextWeek: function () { + return 'dddd [օրը ժամը] LT'; + }, + lastWeek: function () { + return '[անցած] dddd [օրը ժամը] LT'; + }, + sameElse: 'L', + }, + relativeTime: { + future: '%s հետո', + past: '%s առաջ', + s: 'մի քանի վայրկյան', + ss: '%d վայրկյան', + m: 'րոպե', + mm: '%d րոպե', + h: 'ժամ', + hh: '%d ժամ', + d: 'օր', + dd: '%d օր', + M: 'ամիս', + MM: '%d ամիս', + y: 'տարի', + yy: '%d տարի', + }, + meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/, + isPM: function (input) { + return /^(ցերեկվա|երեկոյան)$/.test(input); + }, + meridiem: function (hour) { + if (hour < 4) { + return 'գիշերվա'; + } else if (hour < 12) { + return 'առավոտվա'; + } else if (hour < 17) { + return 'ցերեկվա'; + } else { + return 'երեկոյան'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}|\d{1,2}-(ին|րդ)/, + ordinal: function (number, period) { + switch (period) { + case 'DDD': + case 'w': + case 'W': + case 'DDDo': + if (number === 1) { + return number + '-ին'; + } + return number + '-րդ'; + default: + return number; + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('id', { + months: 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des'.split('_'), + weekdays: 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'), + weekdaysShort: 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'), + weekdaysMin: 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'), + longDateFormat: { + LT: 'HH.mm', + LTS: 'HH.mm.ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY [pukul] HH.mm', + LLLL: 'dddd, D MMMM YYYY [pukul] HH.mm', + }, + meridiemParse: /pagi|siang|sore|malam/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'pagi') { + return hour; + } else if (meridiem === 'siang') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'sore' || meridiem === 'malam') { + return hour + 12; + } + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 11) { + return 'pagi'; + } else if (hours < 15) { + return 'siang'; + } else if (hours < 19) { + return 'sore'; + } else { + return 'malam'; + } + }, + calendar: { + sameDay: '[Hari ini pukul] LT', + nextDay: '[Besok pukul] LT', + nextWeek: 'dddd [pukul] LT', + lastDay: '[Kemarin pukul] LT', + lastWeek: 'dddd [lalu pukul] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dalam %s', + past: '%s yang lalu', + s: 'beberapa detik', + ss: '%d detik', + m: 'semenit', + mm: '%d menit', + h: 'sejam', + hh: '%d jam', + d: 'sehari', + dd: '%d hari', + M: 'sebulan', + MM: '%d bulan', + y: 'setahun', + yy: '%d tahun', + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function plural$2(n) { + if (n % 100 === 11) { + return true; + } else if (n % 10 === 1) { + return false; + } + return true; + } + function translate$5(number, withoutSuffix, key, isFuture) { + var result = number + ' '; + switch (key) { + case 's': + return withoutSuffix || isFuture + ? 'nokkrar sekúndur' + : 'nokkrum sekúndum'; + case 'ss': + if (plural$2(number)) { + return ( + result + + (withoutSuffix || isFuture ? 'sekúndur' : 'sekúndum') + ); + } + return result + 'sekúnda'; + case 'm': + return withoutSuffix ? 'mínúta' : 'mínútu'; + case 'mm': + if (plural$2(number)) { + return ( + result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum') + ); + } else if (withoutSuffix) { + return result + 'mínúta'; + } + return result + 'mínútu'; + case 'hh': + if (plural$2(number)) { + return ( + result + + (withoutSuffix || isFuture + ? 'klukkustundir' + : 'klukkustundum') + ); + } + return result + 'klukkustund'; + case 'd': + if (withoutSuffix) { + return 'dagur'; + } + return isFuture ? 'dag' : 'degi'; + case 'dd': + if (plural$2(number)) { + if (withoutSuffix) { + return result + 'dagar'; + } + return result + (isFuture ? 'daga' : 'dögum'); + } else if (withoutSuffix) { + return result + 'dagur'; + } + return result + (isFuture ? 'dag' : 'degi'); + case 'M': + if (withoutSuffix) { + return 'mánuður'; + } + return isFuture ? 'mánuð' : 'mánuði'; + case 'MM': + if (plural$2(number)) { + if (withoutSuffix) { + return result + 'mánuðir'; + } + return result + (isFuture ? 'mánuði' : 'mánuðum'); + } else if (withoutSuffix) { + return result + 'mánuður'; + } + return result + (isFuture ? 'mánuð' : 'mánuði'); + case 'y': + return withoutSuffix || isFuture ? 'ár' : 'ári'; + case 'yy': + if (plural$2(number)) { + return result + (withoutSuffix || isFuture ? 'ár' : 'árum'); + } + return result + (withoutSuffix || isFuture ? 'ár' : 'ári'); + } + } + + hooks.defineLocale('is', { + months: 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split( + '_' + ), + monthsShort: 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'), + weekdays: + 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split( + '_' + ), + weekdaysShort: 'sun_mán_þri_mið_fim_fös_lau'.split('_'), + weekdaysMin: 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY [kl.] H:mm', + LLLL: 'dddd, D. MMMM YYYY [kl.] H:mm', + }, + calendar: { + sameDay: '[í dag kl.] LT', + nextDay: '[á morgun kl.] LT', + nextWeek: 'dddd [kl.] LT', + lastDay: '[í gær kl.] LT', + lastWeek: '[síðasta] dddd [kl.] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'eftir %s', + past: 'fyrir %s síðan', + s: translate$5, + ss: translate$5, + m: translate$5, + mm: translate$5, + h: 'klukkustund', + hh: translate$5, + d: translate$5, + dd: translate$5, + M: translate$5, + MM: translate$5, + y: translate$5, + yy: translate$5, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('it-ch', { + months: 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split( + '_' + ), + monthsShort: 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), + weekdays: 'domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato'.split( + '_' + ), + weekdaysShort: 'dom_lun_mar_mer_gio_ven_sab'.split('_'), + weekdaysMin: 'do_lu_ma_me_gi_ve_sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Oggi alle] LT', + nextDay: '[Domani alle] LT', + nextWeek: 'dddd [alle] LT', + lastDay: '[Ieri alle] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[la scorsa] dddd [alle] LT'; + default: + return '[lo scorso] dddd [alle] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: function (s) { + return (/^[0-9].+$/.test(s) ? 'tra' : 'in') + ' ' + s; + }, + past: '%s fa', + s: 'alcuni secondi', + ss: '%d secondi', + m: 'un minuto', + mm: '%d minuti', + h: "un'ora", + hh: '%d ore', + d: 'un giorno', + dd: '%d giorni', + M: 'un mese', + MM: '%d mesi', + y: 'un anno', + yy: '%d anni', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('it', { + months: 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split( + '_' + ), + monthsShort: 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), + weekdays: 'domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato'.split( + '_' + ), + weekdaysShort: 'dom_lun_mar_mer_gio_ven_sab'.split('_'), + weekdaysMin: 'do_lu_ma_me_gi_ve_sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: function () { + return ( + '[Oggi a' + + (this.hours() > 1 ? 'lle ' : this.hours() === 0 ? ' ' : "ll'") + + ']LT' + ); + }, + nextDay: function () { + return ( + '[Domani a' + + (this.hours() > 1 ? 'lle ' : this.hours() === 0 ? ' ' : "ll'") + + ']LT' + ); + }, + nextWeek: function () { + return ( + 'dddd [a' + + (this.hours() > 1 ? 'lle ' : this.hours() === 0 ? ' ' : "ll'") + + ']LT' + ); + }, + lastDay: function () { + return ( + '[Ieri a' + + (this.hours() > 1 ? 'lle ' : this.hours() === 0 ? ' ' : "ll'") + + ']LT' + ); + }, + lastWeek: function () { + switch (this.day()) { + case 0: + return ( + '[La scorsa] dddd [a' + + (this.hours() > 1 + ? 'lle ' + : this.hours() === 0 + ? ' ' + : "ll'") + + ']LT' + ); + default: + return ( + '[Lo scorso] dddd [a' + + (this.hours() > 1 + ? 'lle ' + : this.hours() === 0 + ? ' ' + : "ll'") + + ']LT' + ); + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'tra %s', + past: '%s fa', + s: 'alcuni secondi', + ss: '%d secondi', + m: 'un minuto', + mm: '%d minuti', + h: "un'ora", + hh: '%d ore', + d: 'un giorno', + dd: '%d giorni', + w: 'una settimana', + ww: '%d settimane', + M: 'un mese', + MM: '%d mesi', + y: 'un anno', + yy: '%d anni', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ja', { + eras: [ + { + since: '2019-05-01', + offset: 1, + name: '令和', + narrow: '㋿', + abbr: 'R', + }, + { + since: '1989-01-08', + until: '2019-04-30', + offset: 1, + name: '平成', + narrow: '㍻', + abbr: 'H', + }, + { + since: '1926-12-25', + until: '1989-01-07', + offset: 1, + name: '昭和', + narrow: '㍼', + abbr: 'S', + }, + { + since: '1912-07-30', + until: '1926-12-24', + offset: 1, + name: '大正', + narrow: '㍽', + abbr: 'T', + }, + { + since: '1873-01-01', + until: '1912-07-29', + offset: 6, + name: '明治', + narrow: '㍾', + abbr: 'M', + }, + { + since: '0001-01-01', + until: '1873-12-31', + offset: 1, + name: '西暦', + narrow: 'AD', + abbr: 'AD', + }, + { + since: '0000-12-31', + until: -Infinity, + offset: 1, + name: '紀元前', + narrow: 'BC', + abbr: 'BC', + }, + ], + eraYearOrdinalRegex: /(元|\d+)年/, + eraYearOrdinalParse: function (input, match) { + return match[1] === '元' ? 1 : parseInt(match[1] || input, 10); + }, + months: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), + monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split( + '_' + ), + weekdays: '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'), + weekdaysShort: '日_月_火_水_木_金_土'.split('_'), + weekdaysMin: '日_月_火_水_木_金_土'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY/MM/DD', + LL: 'YYYY年M月D日', + LLL: 'YYYY年M月D日 HH:mm', + LLLL: 'YYYY年M月D日 dddd HH:mm', + l: 'YYYY/MM/DD', + ll: 'YYYY年M月D日', + lll: 'YYYY年M月D日 HH:mm', + llll: 'YYYY年M月D日(ddd) HH:mm', + }, + meridiemParse: /午前|午後/i, + isPM: function (input) { + return input === '午後'; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return '午前'; + } else { + return '午後'; + } + }, + calendar: { + sameDay: '[今日] LT', + nextDay: '[明日] LT', + nextWeek: function (now) { + if (now.week() !== this.week()) { + return '[来週]dddd LT'; + } else { + return 'dddd LT'; + } + }, + lastDay: '[昨日] LT', + lastWeek: function (now) { + if (this.week() !== now.week()) { + return '[先週]dddd LT'; + } else { + return 'dddd LT'; + } + }, + sameElse: 'L', + }, + dayOfMonthOrdinalParse: /\d{1,2}日/, + ordinal: function (number, period) { + switch (period) { + case 'y': + return number === 1 ? '元年' : number + '年'; + case 'd': + case 'D': + case 'DDD': + return number + '日'; + default: + return number; + } + }, + relativeTime: { + future: '%s後', + past: '%s前', + s: '数秒', + ss: '%d秒', + m: '1分', + mm: '%d分', + h: '1時間', + hh: '%d時間', + d: '1日', + dd: '%d日', + M: '1ヶ月', + MM: '%dヶ月', + y: '1年', + yy: '%d年', + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('jv', { + months: 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'), + weekdays: 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'), + weekdaysShort: 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'), + weekdaysMin: 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'), + longDateFormat: { + LT: 'HH.mm', + LTS: 'HH.mm.ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY [pukul] HH.mm', + LLLL: 'dddd, D MMMM YYYY [pukul] HH.mm', + }, + meridiemParse: /enjing|siyang|sonten|ndalu/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'enjing') { + return hour; + } else if (meridiem === 'siyang') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'sonten' || meridiem === 'ndalu') { + return hour + 12; + } + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 11) { + return 'enjing'; + } else if (hours < 15) { + return 'siyang'; + } else if (hours < 19) { + return 'sonten'; + } else { + return 'ndalu'; + } + }, + calendar: { + sameDay: '[Dinten puniko pukul] LT', + nextDay: '[Mbenjang pukul] LT', + nextWeek: 'dddd [pukul] LT', + lastDay: '[Kala wingi pukul] LT', + lastWeek: 'dddd [kepengker pukul] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'wonten ing %s', + past: '%s ingkang kepengker', + s: 'sawetawis detik', + ss: '%d detik', + m: 'setunggal menit', + mm: '%d menit', + h: 'setunggal jam', + hh: '%d jam', + d: 'sedinten', + dd: '%d dinten', + M: 'sewulan', + MM: '%d wulan', + y: 'setaun', + yy: '%d taun', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ka', { + months: 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split( + '_' + ), + monthsShort: 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'), + weekdays: { + standalone: + 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split( + '_' + ), + format: 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split( + '_' + ), + isFormat: /(წინა|შემდეგ)/, + }, + weekdaysShort: 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'), + weekdaysMin: 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[დღეს] LT[-ზე]', + nextDay: '[ხვალ] LT[-ზე]', + lastDay: '[გუშინ] LT[-ზე]', + nextWeek: '[შემდეგ] dddd LT[-ზე]', + lastWeek: '[წინა] dddd LT-ზე', + sameElse: 'L', + }, + relativeTime: { + future: function (s) { + return s.replace( + /(წამ|წუთ|საათ|წელ|დღ|თვ)(ი|ე)/, + function ($0, $1, $2) { + return $2 === 'ი' ? $1 + 'ში' : $1 + $2 + 'ში'; + } + ); + }, + past: function (s) { + if (/(წამი|წუთი|საათი|დღე|თვე)/.test(s)) { + return s.replace(/(ი|ე)$/, 'ის წინ'); + } + if (/წელი/.test(s)) { + return s.replace(/წელი$/, 'წლის წინ'); + } + return s; + }, + s: 'რამდენიმე წამი', + ss: '%d წამი', + m: 'წუთი', + mm: '%d წუთი', + h: 'საათი', + hh: '%d საათი', + d: 'დღე', + dd: '%d დღე', + M: 'თვე', + MM: '%d თვე', + y: 'წელი', + yy: '%d წელი', + }, + dayOfMonthOrdinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/, + ordinal: function (number) { + if (number === 0) { + return number; + } + if (number === 1) { + return number + '-ლი'; + } + if ( + number < 20 || + (number <= 100 && number % 20 === 0) || + number % 100 === 0 + ) { + return 'მე-' + number; + } + return number + '-ე'; + }, + week: { + dow: 1, + doy: 7, + }, + }); + + //! moment.js locale configuration + + var suffixes$1 = { + 0: '-ші', + 1: '-ші', + 2: '-ші', + 3: '-ші', + 4: '-ші', + 5: '-ші', + 6: '-шы', + 7: '-ші', + 8: '-ші', + 9: '-шы', + 10: '-шы', + 20: '-шы', + 30: '-шы', + 40: '-шы', + 50: '-ші', + 60: '-шы', + 70: '-ші', + 80: '-ші', + 90: '-шы', + 100: '-ші', + }; + + hooks.defineLocale('kk', { + months: 'қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан'.split( + '_' + ), + monthsShort: 'қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел'.split('_'), + weekdays: 'жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі'.split( + '_' + ), + weekdaysShort: 'жек_дүй_сей_сәр_бей_жұм_сен'.split('_'), + weekdaysMin: 'жк_дй_сй_ср_бй_жм_сн'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Бүгін сағат] LT', + nextDay: '[Ертең сағат] LT', + nextWeek: 'dddd [сағат] LT', + lastDay: '[Кеше сағат] LT', + lastWeek: '[Өткен аптаның] dddd [сағат] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s ішінде', + past: '%s бұрын', + s: 'бірнеше секунд', + ss: '%d секунд', + m: 'бір минут', + mm: '%d минут', + h: 'бір сағат', + hh: '%d сағат', + d: 'бір күн', + dd: '%d күн', + M: 'бір ай', + MM: '%d ай', + y: 'бір жыл', + yy: '%d жыл', + }, + dayOfMonthOrdinalParse: /\d{1,2}-(ші|шы)/, + ordinal: function (number) { + var a = number % 10, + b = number >= 100 ? 100 : null; + return number + (suffixes$1[number] || suffixes$1[a] || suffixes$1[b]); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$9 = { + 1: '១', + 2: '២', + 3: '៣', + 4: '៤', + 5: '៥', + 6: '៦', + 7: '៧', + 8: '៨', + 9: '៩', + 0: '០', + }, + numberMap$8 = { + '១': '1', + '២': '2', + '៣': '3', + '៤': '4', + '៥': '5', + '៦': '6', + '៧': '7', + '៨': '8', + '៩': '9', + '០': '0', + }; + + hooks.defineLocale('km', { + months: 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split( + '_' + ), + monthsShort: + 'មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split( + '_' + ), + weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), + weekdaysShort: 'អា_ច_អ_ព_ព្រ_សុ_ស'.split('_'), + weekdaysMin: 'អា_ច_អ_ព_ព្រ_សុ_ស'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + meridiemParse: /ព្រឹក|ល្ងាច/, + isPM: function (input) { + return input === 'ល្ងាច'; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ព្រឹក'; + } else { + return 'ល្ងាច'; + } + }, + calendar: { + sameDay: '[ថ្ងៃនេះ ម៉ោង] LT', + nextDay: '[ស្អែក ម៉ោង] LT', + nextWeek: 'dddd [ម៉ោង] LT', + lastDay: '[ម្សិលមិញ ម៉ោង] LT', + lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%sទៀត', + past: '%sមុន', + s: 'ប៉ុន្មានវិនាទី', + ss: '%d វិនាទី', + m: 'មួយនាទី', + mm: '%d នាទី', + h: 'មួយម៉ោង', + hh: '%d ម៉ោង', + d: 'មួយថ្ងៃ', + dd: '%d ថ្ងៃ', + M: 'មួយខែ', + MM: '%d ខែ', + y: 'មួយឆ្នាំ', + yy: '%d ឆ្នាំ', + }, + dayOfMonthOrdinalParse: /ទី\d{1,2}/, + ordinal: 'ទី%d', + preparse: function (string) { + return string.replace(/[១២៣៤៥៦៧៨៩០]/g, function (match) { + return numberMap$8[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$9[match]; + }); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$a = { + 1: '೧', + 2: '೨', + 3: '೩', + 4: '೪', + 5: '೫', + 6: '೬', + 7: '೭', + 8: '೮', + 9: '೯', + 0: '೦', + }, + numberMap$9 = { + '೧': '1', + '೨': '2', + '೩': '3', + '೪': '4', + '೫': '5', + '೬': '6', + '೭': '7', + '೮': '8', + '೯': '9', + '೦': '0', + }; + + hooks.defineLocale('kn', { + months: 'ಜನವರಿ_ಫೆಬ್ರವರಿ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬರ್_ಅಕ್ಟೋಬರ್_ನವೆಂಬರ್_ಡಿಸೆಂಬರ್'.split( + '_' + ), + monthsShort: + 'ಜನ_ಫೆಬ್ರ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂ_ಅಕ್ಟೋ_ನವೆಂ_ಡಿಸೆಂ'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'ಭಾನುವಾರ_ಸೋಮವಾರ_ಮಂಗಳವಾರ_ಬುಧವಾರ_ಗುರುವಾರ_ಶುಕ್ರವಾರ_ಶನಿವಾರ'.split( + '_' + ), + weekdaysShort: 'ಭಾನು_ಸೋಮ_ಮಂಗಳ_ಬುಧ_ಗುರು_ಶುಕ್ರ_ಶನಿ'.split('_'), + weekdaysMin: 'ಭಾ_ಸೋ_ಮಂ_ಬು_ಗು_ಶು_ಶ'.split('_'), + longDateFormat: { + LT: 'A h:mm', + LTS: 'A h:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm', + LLLL: 'dddd, D MMMM YYYY, A h:mm', + }, + calendar: { + sameDay: '[ಇಂದು] LT', + nextDay: '[ನಾಳೆ] LT', + nextWeek: 'dddd, LT', + lastDay: '[ನಿನ್ನೆ] LT', + lastWeek: '[ಕೊನೆಯ] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s ನಂತರ', + past: '%s ಹಿಂದೆ', + s: 'ಕೆಲವು ಕ್ಷಣಗಳು', + ss: '%d ಸೆಕೆಂಡುಗಳು', + m: 'ಒಂದು ನಿಮಿಷ', + mm: '%d ನಿಮಿಷ', + h: 'ಒಂದು ಗಂಟೆ', + hh: '%d ಗಂಟೆ', + d: 'ಒಂದು ದಿನ', + dd: '%d ದಿನ', + M: 'ಒಂದು ತಿಂಗಳು', + MM: '%d ತಿಂಗಳು', + y: 'ಒಂದು ವರ್ಷ', + yy: '%d ವರ್ಷ', + }, + preparse: function (string) { + return string.replace(/[೧೨೩೪೫೬೭೮೯೦]/g, function (match) { + return numberMap$9[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$a[match]; + }); + }, + meridiemParse: /ರಾತ್ರಿ|ಬೆಳಿಗ್ಗೆ|ಮಧ್ಯಾಹ್ನ|ಸಂಜೆ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'ರಾತ್ರಿ') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'ಬೆಳಿಗ್ಗೆ') { + return hour; + } else if (meridiem === 'ಮಧ್ಯಾಹ್ನ') { + return hour >= 10 ? hour : hour + 12; + } else if (meridiem === 'ಸಂಜೆ') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'ರಾತ್ರಿ'; + } else if (hour < 10) { + return 'ಬೆಳಿಗ್ಗೆ'; + } else if (hour < 17) { + return 'ಮಧ್ಯಾಹ್ನ'; + } else if (hour < 20) { + return 'ಸಂಜೆ'; + } else { + return 'ರಾತ್ರಿ'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}(ನೇ)/, + ordinal: function (number) { + return number + 'ನೇ'; + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ko', { + months: '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), + monthsShort: '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split( + '_' + ), + weekdays: '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'), + weekdaysShort: '일_월_화_수_목_금_토'.split('_'), + weekdaysMin: '일_월_화_수_목_금_토'.split('_'), + longDateFormat: { + LT: 'A h:mm', + LTS: 'A h:mm:ss', + L: 'YYYY.MM.DD.', + LL: 'YYYY년 MMMM D일', + LLL: 'YYYY년 MMMM D일 A h:mm', + LLLL: 'YYYY년 MMMM D일 dddd A h:mm', + l: 'YYYY.MM.DD.', + ll: 'YYYY년 MMMM D일', + lll: 'YYYY년 MMMM D일 A h:mm', + llll: 'YYYY년 MMMM D일 dddd A h:mm', + }, + calendar: { + sameDay: '오늘 LT', + nextDay: '내일 LT', + nextWeek: 'dddd LT', + lastDay: '어제 LT', + lastWeek: '지난주 dddd LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s 후', + past: '%s 전', + s: '몇 초', + ss: '%d초', + m: '1분', + mm: '%d분', + h: '한 시간', + hh: '%d시간', + d: '하루', + dd: '%d일', + M: '한 달', + MM: '%d달', + y: '일 년', + yy: '%d년', + }, + dayOfMonthOrdinalParse: /\d{1,2}(일|월|주)/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + '일'; + case 'M': + return number + '월'; + case 'w': + case 'W': + return number + '주'; + default: + return number; + } + }, + meridiemParse: /오전|오후/, + isPM: function (token) { + return token === '오후'; + }, + meridiem: function (hour, minute, isUpper) { + return hour < 12 ? '오전' : '오후'; + }, + }); + + //! moment.js locale configuration + + var symbolMap$b = { + 1: '١', + 2: '٢', + 3: '٣', + 4: '٤', + 5: '٥', + 6: '٦', + 7: '٧', + 8: '٨', + 9: '٩', + 0: '٠', + }, + numberMap$a = { + '١': '1', + '٢': '2', + '٣': '3', + '٤': '4', + '٥': '5', + '٦': '6', + '٧': '7', + '٨': '8', + '٩': '9', + '٠': '0', + }, + months$8 = [ + 'کانونی دووەم', + 'شوبات', + 'ئازار', + 'نیسان', + 'ئایار', + 'حوزەیران', + 'تەمموز', + 'ئاب', + 'ئەیلوول', + 'تشرینی یەكەم', + 'تشرینی دووەم', + 'كانونی یەکەم', + ]; + + hooks.defineLocale('ku', { + months: months$8, + monthsShort: months$8, + weekdays: + 'یه‌كشه‌ممه‌_دووشه‌ممه‌_سێشه‌ممه‌_چوارشه‌ممه‌_پێنجشه‌ممه‌_هه‌ینی_شه‌ممه‌'.split( + '_' + ), + weekdaysShort: + 'یه‌كشه‌م_دووشه‌م_سێشه‌م_چوارشه‌م_پێنجشه‌م_هه‌ینی_شه‌ممه‌'.split('_'), + weekdaysMin: 'ی_د_س_چ_پ_ه_ش'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + meridiemParse: /ئێواره‌|به‌یانی/, + isPM: function (input) { + return /ئێواره‌/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'به‌یانی'; + } else { + return 'ئێواره‌'; + } + }, + calendar: { + sameDay: '[ئه‌مرۆ كاتژمێر] LT', + nextDay: '[به‌یانی كاتژمێر] LT', + nextWeek: 'dddd [كاتژمێر] LT', + lastDay: '[دوێنێ كاتژمێر] LT', + lastWeek: 'dddd [كاتژمێر] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'له‌ %s', + past: '%s', + s: 'چه‌ند چركه‌یه‌ك', + ss: 'چركه‌ %d', + m: 'یه‌ك خوله‌ك', + mm: '%d خوله‌ك', + h: 'یه‌ك كاتژمێر', + hh: '%d كاتژمێر', + d: 'یه‌ك ڕۆژ', + dd: '%d ڕۆژ', + M: 'یه‌ك مانگ', + MM: '%d مانگ', + y: 'یه‌ك ساڵ', + yy: '%d ساڵ', + }, + preparse: function (string) { + return string + .replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) { + return numberMap$a[match]; + }) + .replace(/،/g, ','); + }, + postformat: function (string) { + return string + .replace(/\d/g, function (match) { + return symbolMap$b[match]; + }) + .replace(/,/g, '،'); + }, + week: { + dow: 6, // Saturday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var suffixes$2 = { + 0: '-чү', + 1: '-чи', + 2: '-чи', + 3: '-чү', + 4: '-чү', + 5: '-чи', + 6: '-чы', + 7: '-чи', + 8: '-чи', + 9: '-чу', + 10: '-чу', + 20: '-чы', + 30: '-чу', + 40: '-чы', + 50: '-чү', + 60: '-чы', + 70: '-чи', + 80: '-чи', + 90: '-чу', + 100: '-чү', + }; + + hooks.defineLocale('ky', { + months: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split( + '_' + ), + monthsShort: 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split( + '_' + ), + weekdays: 'Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби'.split( + '_' + ), + weekdaysShort: 'Жек_Дүй_Шей_Шар_Бей_Жум_Ише'.split('_'), + weekdaysMin: 'Жк_Дй_Шй_Шр_Бй_Жм_Иш'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Бүгүн саат] LT', + nextDay: '[Эртең саат] LT', + nextWeek: 'dddd [саат] LT', + lastDay: '[Кечээ саат] LT', + lastWeek: '[Өткөн аптанын] dddd [күнү] [саат] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s ичинде', + past: '%s мурун', + s: 'бирнече секунд', + ss: '%d секунд', + m: 'бир мүнөт', + mm: '%d мүнөт', + h: 'бир саат', + hh: '%d саат', + d: 'бир күн', + dd: '%d күн', + M: 'бир ай', + MM: '%d ай', + y: 'бир жыл', + yy: '%d жыл', + }, + dayOfMonthOrdinalParse: /\d{1,2}-(чи|чы|чү|чу)/, + ordinal: function (number) { + var a = number % 10, + b = number >= 100 ? 100 : null; + return number + (suffixes$2[number] || suffixes$2[a] || suffixes$2[b]); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function processRelativeTime$6(number, withoutSuffix, key, isFuture) { + var format = { + m: ['eng Minutt', 'enger Minutt'], + h: ['eng Stonn', 'enger Stonn'], + d: ['een Dag', 'engem Dag'], + M: ['ee Mount', 'engem Mount'], + y: ['ee Joer', 'engem Joer'], + }; + return withoutSuffix ? format[key][0] : format[key][1]; + } + function processFutureTime(string) { + var number = string.substr(0, string.indexOf(' ')); + if (eifelerRegelAppliesToNumber(number)) { + return 'a ' + string; + } + return 'an ' + string; + } + function processPastTime(string) { + var number = string.substr(0, string.indexOf(' ')); + if (eifelerRegelAppliesToNumber(number)) { + return 'viru ' + string; + } + return 'virun ' + string; + } + /** + * Returns true if the word before the given number loses the '-n' ending. + * e.g. 'an 10 Deeg' but 'a 5 Deeg' + * + * @param number {integer} + * @returns {boolean} + */ + function eifelerRegelAppliesToNumber(number) { + number = parseInt(number, 10); + if (isNaN(number)) { + return false; + } + if (number < 0) { + // Negative Number --> always true + return true; + } else if (number < 10) { + // Only 1 digit + if (4 <= number && number <= 7) { + return true; + } + return false; + } else if (number < 100) { + // 2 digits + var lastDigit = number % 10, + firstDigit = number / 10; + if (lastDigit === 0) { + return eifelerRegelAppliesToNumber(firstDigit); + } + return eifelerRegelAppliesToNumber(lastDigit); + } else if (number < 10000) { + // 3 or 4 digits --> recursively check first digit + while (number >= 10) { + number = number / 10; + } + return eifelerRegelAppliesToNumber(number); + } else { + // Anything larger than 4 digits: recursively check first n-3 digits + number = number / 1000; + return eifelerRegelAppliesToNumber(number); + } + } + + hooks.defineLocale('lb', { + months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split( + '_' + ), + monthsShort: + 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split( + '_' + ), + monthsParseExact: true, + weekdays: + 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split( + '_' + ), + weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'), + weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm [Auer]', + LTS: 'H:mm:ss [Auer]', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm [Auer]', + LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]', + }, + calendar: { + sameDay: '[Haut um] LT', + sameElse: 'L', + nextDay: '[Muer um] LT', + nextWeek: 'dddd [um] LT', + lastDay: '[Gëschter um] LT', + lastWeek: function () { + // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule + switch (this.day()) { + case 2: + case 4: + return '[Leschten] dddd [um] LT'; + default: + return '[Leschte] dddd [um] LT'; + } + }, + }, + relativeTime: { + future: processFutureTime, + past: processPastTime, + s: 'e puer Sekonnen', + ss: '%d Sekonnen', + m: processRelativeTime$6, + mm: '%d Minutten', + h: processRelativeTime$6, + hh: '%d Stonnen', + d: processRelativeTime$6, + dd: '%d Deeg', + M: processRelativeTime$6, + MM: '%d Méint', + y: processRelativeTime$6, + yy: '%d Joer', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('lo', { + months: 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split( + '_' + ), + monthsShort: + 'ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ'.split( + '_' + ), + weekdays: 'ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'), + weekdaysShort: 'ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ'.split('_'), + weekdaysMin: 'ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'ວັນdddd D MMMM YYYY HH:mm', + }, + meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/, + isPM: function (input) { + return input === 'ຕອນແລງ'; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ຕອນເຊົ້າ'; + } else { + return 'ຕອນແລງ'; + } + }, + calendar: { + sameDay: '[ມື້ນີ້ເວລາ] LT', + nextDay: '[ມື້ອື່ນເວລາ] LT', + nextWeek: '[ວັນ]dddd[ໜ້າເວລາ] LT', + lastDay: '[ມື້ວານນີ້ເວລາ] LT', + lastWeek: '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'ອີກ %s', + past: '%sຜ່ານມາ', + s: 'ບໍ່ເທົ່າໃດວິນາທີ', + ss: '%d ວິນາທີ', + m: '1 ນາທີ', + mm: '%d ນາທີ', + h: '1 ຊົ່ວໂມງ', + hh: '%d ຊົ່ວໂມງ', + d: '1 ມື້', + dd: '%d ມື້', + M: '1 ເດືອນ', + MM: '%d ເດືອນ', + y: '1 ປີ', + yy: '%d ປີ', + }, + dayOfMonthOrdinalParse: /(ທີ່)\d{1,2}/, + ordinal: function (number) { + return 'ທີ່' + number; + }, + }); + + //! moment.js locale configuration + + var units = { + ss: 'sekundė_sekundžių_sekundes', + m: 'minutė_minutės_minutę', + mm: 'minutės_minučių_minutes', + h: 'valanda_valandos_valandą', + hh: 'valandos_valandų_valandas', + d: 'diena_dienos_dieną', + dd: 'dienos_dienų_dienas', + M: 'mėnuo_mėnesio_mėnesį', + MM: 'mėnesiai_mėnesių_mėnesius', + y: 'metai_metų_metus', + yy: 'metai_metų_metus', + }; + function translateSeconds(number, withoutSuffix, key, isFuture) { + if (withoutSuffix) { + return 'kelios sekundės'; + } else { + return isFuture ? 'kelių sekundžių' : 'kelias sekundes'; + } + } + function translateSingular(number, withoutSuffix, key, isFuture) { + return withoutSuffix + ? forms(key)[0] + : isFuture + ? forms(key)[1] + : forms(key)[2]; + } + function special(number) { + return number % 10 === 0 || (number > 10 && number < 20); + } + function forms(key) { + return units[key].split('_'); + } + function translate$6(number, withoutSuffix, key, isFuture) { + var result = number + ' '; + if (number === 1) { + return ( + result + translateSingular(number, withoutSuffix, key[0], isFuture) + ); + } else if (withoutSuffix) { + return result + (special(number) ? forms(key)[1] : forms(key)[0]); + } else { + if (isFuture) { + return result + forms(key)[1]; + } else { + return result + (special(number) ? forms(key)[1] : forms(key)[2]); + } + } + } + hooks.defineLocale('lt', { + months: { + format: 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split( + '_' + ), + standalone: + 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split( + '_' + ), + isFormat: /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/, + }, + monthsShort: 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'), + weekdays: { + format: 'sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį'.split( + '_' + ), + standalone: + 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split( + '_' + ), + isFormat: /dddd HH:mm/, + }, + weekdaysShort: 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'), + weekdaysMin: 'S_P_A_T_K_Pn_Š'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: 'YYYY [m.] MMMM D [d.]', + LLL: 'YYYY [m.] MMMM D [d.], HH:mm [val.]', + LLLL: 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]', + l: 'YYYY-MM-DD', + ll: 'YYYY [m.] MMMM D [d.]', + lll: 'YYYY [m.] MMMM D [d.], HH:mm [val.]', + llll: 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]', + }, + calendar: { + sameDay: '[Šiandien] LT', + nextDay: '[Rytoj] LT', + nextWeek: 'dddd LT', + lastDay: '[Vakar] LT', + lastWeek: '[Praėjusį] dddd LT', + sameElse: 'L', + }, + relativeTime: { + future: 'po %s', + past: 'prieš %s', + s: translateSeconds, + ss: translate$6, + m: translateSingular, + mm: translate$6, + h: translateSingular, + hh: translate$6, + d: translateSingular, + dd: translate$6, + M: translateSingular, + MM: translate$6, + y: translateSingular, + yy: translate$6, + }, + dayOfMonthOrdinalParse: /\d{1,2}-oji/, + ordinal: function (number) { + return number + '-oji'; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var units$1 = { + ss: 'sekundes_sekundēm_sekunde_sekundes'.split('_'), + m: 'minūtes_minūtēm_minūte_minūtes'.split('_'), + mm: 'minūtes_minūtēm_minūte_minūtes'.split('_'), + h: 'stundas_stundām_stunda_stundas'.split('_'), + hh: 'stundas_stundām_stunda_stundas'.split('_'), + d: 'dienas_dienām_diena_dienas'.split('_'), + dd: 'dienas_dienām_diena_dienas'.split('_'), + M: 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'), + MM: 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'), + y: 'gada_gadiem_gads_gadi'.split('_'), + yy: 'gada_gadiem_gads_gadi'.split('_'), + }; + /** + * @param withoutSuffix boolean true = a length of time; false = before/after a period of time. + */ + function format$1(forms, number, withoutSuffix) { + if (withoutSuffix) { + // E.g. "21 minūte", "3 minūtes". + return number % 10 === 1 && number % 100 !== 11 ? forms[2] : forms[3]; + } else { + // E.g. "21 minūtes" as in "pēc 21 minūtes". + // E.g. "3 minūtēm" as in "pēc 3 minūtēm". + return number % 10 === 1 && number % 100 !== 11 ? forms[0] : forms[1]; + } + } + function relativeTimeWithPlural$1(number, withoutSuffix, key) { + return number + ' ' + format$1(units$1[key], number, withoutSuffix); + } + function relativeTimeWithSingular(number, withoutSuffix, key) { + return format$1(units$1[key], number, withoutSuffix); + } + function relativeSeconds(number, withoutSuffix) { + return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm'; + } + + hooks.defineLocale('lv', { + months: 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split( + '_' + ), + monthsShort: 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'), + weekdays: + 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split( + '_' + ), + weekdaysShort: 'Sv_P_O_T_C_Pk_S'.split('_'), + weekdaysMin: 'Sv_P_O_T_C_Pk_S'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY.', + LL: 'YYYY. [gada] D. MMMM', + LLL: 'YYYY. [gada] D. MMMM, HH:mm', + LLLL: 'YYYY. [gada] D. MMMM, dddd, HH:mm', + }, + calendar: { + sameDay: '[Šodien pulksten] LT', + nextDay: '[Rīt pulksten] LT', + nextWeek: 'dddd [pulksten] LT', + lastDay: '[Vakar pulksten] LT', + lastWeek: '[Pagājušā] dddd [pulksten] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'pēc %s', + past: 'pirms %s', + s: relativeSeconds, + ss: relativeTimeWithPlural$1, + m: relativeTimeWithSingular, + mm: relativeTimeWithPlural$1, + h: relativeTimeWithSingular, + hh: relativeTimeWithPlural$1, + d: relativeTimeWithSingular, + dd: relativeTimeWithPlural$1, + M: relativeTimeWithSingular, + MM: relativeTimeWithPlural$1, + y: relativeTimeWithSingular, + yy: relativeTimeWithPlural$1, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var translator = { + words: { + //Different grammatical cases + ss: ['sekund', 'sekunda', 'sekundi'], + m: ['jedan minut', 'jednog minuta'], + mm: ['minut', 'minuta', 'minuta'], + h: ['jedan sat', 'jednog sata'], + hh: ['sat', 'sata', 'sati'], + dd: ['dan', 'dana', 'dana'], + MM: ['mjesec', 'mjeseca', 'mjeseci'], + yy: ['godina', 'godine', 'godina'], + }, + correctGrammaticalCase: function (number, wordKey) { + return number === 1 + ? wordKey[0] + : number >= 2 && number <= 4 + ? wordKey[1] + : wordKey[2]; + }, + translate: function (number, withoutSuffix, key) { + var wordKey = translator.words[key]; + if (key.length === 1) { + return withoutSuffix ? wordKey[0] : wordKey[1]; + } else { + return ( + number + + ' ' + + translator.correctGrammaticalCase(number, wordKey) + ); + } + }, + }; + + hooks.defineLocale('me', { + months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split( + '_' + ), + monthsShort: + 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'), + monthsParseExact: true, + weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split( + '_' + ), + weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), + weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm', + LLLL: 'dddd, D. MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[danas u] LT', + nextDay: '[sjutra u] LT', + + nextWeek: function () { + switch (this.day()) { + case 0: + return '[u] [nedjelju] [u] LT'; + case 3: + return '[u] [srijedu] [u] LT'; + case 6: + return '[u] [subotu] [u] LT'; + case 1: + case 2: + case 4: + case 5: + return '[u] dddd [u] LT'; + } + }, + lastDay: '[juče u] LT', + lastWeek: function () { + var lastWeekDays = [ + '[prošle] [nedjelje] [u] LT', + '[prošlog] [ponedjeljka] [u] LT', + '[prošlog] [utorka] [u] LT', + '[prošle] [srijede] [u] LT', + '[prošlog] [četvrtka] [u] LT', + '[prošlog] [petka] [u] LT', + '[prošle] [subote] [u] LT', + ]; + return lastWeekDays[this.day()]; + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: 'prije %s', + s: 'nekoliko sekundi', + ss: translator.translate, + m: translator.translate, + mm: translator.translate, + h: translator.translate, + hh: translator.translate, + d: 'dan', + dd: translator.translate, + M: 'mjesec', + MM: translator.translate, + y: 'godinu', + yy: translator.translate, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('mi', { + months: 'Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea'.split( + '_' + ), + monthsShort: + 'Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki'.split( + '_' + ), + monthsRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i, + monthsStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i, + monthsShortRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i, + monthsShortStrictRegex: /(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i, + weekdays: 'Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei'.split('_'), + weekdaysShort: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'), + weekdaysMin: 'Ta_Ma_Tū_We_Tāi_Pa_Hā'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY [i] HH:mm', + LLLL: 'dddd, D MMMM YYYY [i] HH:mm', + }, + calendar: { + sameDay: '[i teie mahana, i] LT', + nextDay: '[apopo i] LT', + nextWeek: 'dddd [i] LT', + lastDay: '[inanahi i] LT', + lastWeek: 'dddd [whakamutunga i] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'i roto i %s', + past: '%s i mua', + s: 'te hēkona ruarua', + ss: '%d hēkona', + m: 'he meneti', + mm: '%d meneti', + h: 'te haora', + hh: '%d haora', + d: 'he ra', + dd: '%d ra', + M: 'he marama', + MM: '%d marama', + y: 'he tau', + yy: '%d tau', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('mk', { + months: 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split( + '_' + ), + monthsShort: 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'), + weekdays: 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split( + '_' + ), + weekdaysShort: 'нед_пон_вто_сре_чет_пет_саб'.split('_'), + weekdaysMin: 'нe_пo_вт_ср_че_пе_сa'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'D.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY H:mm', + LLLL: 'dddd, D MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[Денес во] LT', + nextDay: '[Утре во] LT', + nextWeek: '[Во] dddd [во] LT', + lastDay: '[Вчера во] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + case 3: + case 6: + return '[Изминатата] dddd [во] LT'; + case 1: + case 2: + case 4: + case 5: + return '[Изминатиот] dddd [во] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'за %s', + past: 'пред %s', + s: 'неколку секунди', + ss: '%d секунди', + m: 'една минута', + mm: '%d минути', + h: 'еден час', + hh: '%d часа', + d: 'еден ден', + dd: '%d дена', + M: 'еден месец', + MM: '%d месеци', + y: 'една година', + yy: '%d години', + }, + dayOfMonthOrdinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, + ordinal: function (number) { + var lastDigit = number % 10, + last2Digits = number % 100; + if (number === 0) { + return number + '-ев'; + } else if (last2Digits === 0) { + return number + '-ен'; + } else if (last2Digits > 10 && last2Digits < 20) { + return number + '-ти'; + } else if (lastDigit === 1) { + return number + '-ви'; + } else if (lastDigit === 2) { + return number + '-ри'; + } else if (lastDigit === 7 || lastDigit === 8) { + return number + '-ми'; + } else { + return number + '-ти'; + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ml', { + months: 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split( + '_' + ), + monthsShort: + 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split( + '_' + ), + monthsParseExact: true, + weekdays: + 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split( + '_' + ), + weekdaysShort: 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'), + weekdaysMin: 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'), + longDateFormat: { + LT: 'A h:mm -നു', + LTS: 'A h:mm:ss -നു', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm -നു', + LLLL: 'dddd, D MMMM YYYY, A h:mm -നു', + }, + calendar: { + sameDay: '[ഇന്ന്] LT', + nextDay: '[നാളെ] LT', + nextWeek: 'dddd, LT', + lastDay: '[ഇന്നലെ] LT', + lastWeek: '[കഴിഞ്ഞ] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s കഴിഞ്ഞ്', + past: '%s മുൻപ്', + s: 'അൽപ നിമിഷങ്ങൾ', + ss: '%d സെക്കൻഡ്', + m: 'ഒരു മിനിറ്റ്', + mm: '%d മിനിറ്റ്', + h: 'ഒരു മണിക്കൂർ', + hh: '%d മണിക്കൂർ', + d: 'ഒരു ദിവസം', + dd: '%d ദിവസം', + M: 'ഒരു മാസം', + MM: '%d മാസം', + y: 'ഒരു വർഷം', + yy: '%d വർഷം', + }, + meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if ( + (meridiem === 'രാത്രി' && hour >= 4) || + meridiem === 'ഉച്ച കഴിഞ്ഞ്' || + meridiem === 'വൈകുന്നേരം' + ) { + return hour + 12; + } else { + return hour; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'രാത്രി'; + } else if (hour < 12) { + return 'രാവിലെ'; + } else if (hour < 17) { + return 'ഉച്ച കഴിഞ്ഞ്'; + } else if (hour < 20) { + return 'വൈകുന്നേരം'; + } else { + return 'രാത്രി'; + } + }, + }); + + //! moment.js locale configuration + + function translate$7(number, withoutSuffix, key, isFuture) { + switch (key) { + case 's': + return withoutSuffix ? 'хэдхэн секунд' : 'хэдхэн секундын'; + case 'ss': + return number + (withoutSuffix ? ' секунд' : ' секундын'); + case 'm': + case 'mm': + return number + (withoutSuffix ? ' минут' : ' минутын'); + case 'h': + case 'hh': + return number + (withoutSuffix ? ' цаг' : ' цагийн'); + case 'd': + case 'dd': + return number + (withoutSuffix ? ' өдөр' : ' өдрийн'); + case 'M': + case 'MM': + return number + (withoutSuffix ? ' сар' : ' сарын'); + case 'y': + case 'yy': + return number + (withoutSuffix ? ' жил' : ' жилийн'); + default: + return number; + } + } + + hooks.defineLocale('mn', { + months: 'Нэгдүгээр сар_Хоёрдугаар сар_Гуравдугаар сар_Дөрөвдүгээр сар_Тавдугаар сар_Зургадугаар сар_Долдугаар сар_Наймдугаар сар_Есдүгээр сар_Аравдугаар сар_Арван нэгдүгээр сар_Арван хоёрдугаар сар'.split( + '_' + ), + monthsShort: + '1 сар_2 сар_3 сар_4 сар_5 сар_6 сар_7 сар_8 сар_9 сар_10 сар_11 сар_12 сар'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'Ням_Даваа_Мягмар_Лхагва_Пүрэв_Баасан_Бямба'.split('_'), + weekdaysShort: 'Ням_Дав_Мяг_Лха_Пүр_Баа_Бям'.split('_'), + weekdaysMin: 'Ня_Да_Мя_Лх_Пү_Ба_Бя'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: 'YYYY оны MMMMын D', + LLL: 'YYYY оны MMMMын D HH:mm', + LLLL: 'dddd, YYYY оны MMMMын D HH:mm', + }, + meridiemParse: /ҮӨ|ҮХ/i, + isPM: function (input) { + return input === 'ҮХ'; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ҮӨ'; + } else { + return 'ҮХ'; + } + }, + calendar: { + sameDay: '[Өнөөдөр] LT', + nextDay: '[Маргааш] LT', + nextWeek: '[Ирэх] dddd LT', + lastDay: '[Өчигдөр] LT', + lastWeek: '[Өнгөрсөн] dddd LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s дараа', + past: '%s өмнө', + s: translate$7, + ss: translate$7, + m: translate$7, + mm: translate$7, + h: translate$7, + hh: translate$7, + d: translate$7, + dd: translate$7, + M: translate$7, + MM: translate$7, + y: translate$7, + yy: translate$7, + }, + dayOfMonthOrdinalParse: /\d{1,2} өдөр/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + ' өдөр'; + default: + return number; + } + }, + }); + + //! moment.js locale configuration + + var symbolMap$c = { + 1: '१', + 2: '२', + 3: '३', + 4: '४', + 5: '५', + 6: '६', + 7: '७', + 8: '८', + 9: '९', + 0: '०', + }, + numberMap$b = { + '१': '1', + '२': '2', + '३': '3', + '४': '4', + '५': '5', + '६': '6', + '७': '7', + '८': '8', + '९': '9', + '०': '0', + }; + + function relativeTimeMr(number, withoutSuffix, string, isFuture) { + var output = ''; + if (withoutSuffix) { + switch (string) { + case 's': + output = 'काही सेकंद'; + break; + case 'ss': + output = '%d सेकंद'; + break; + case 'm': + output = 'एक मिनिट'; + break; + case 'mm': + output = '%d मिनिटे'; + break; + case 'h': + output = 'एक तास'; + break; + case 'hh': + output = '%d तास'; + break; + case 'd': + output = 'एक दिवस'; + break; + case 'dd': + output = '%d दिवस'; + break; + case 'M': + output = 'एक महिना'; + break; + case 'MM': + output = '%d महिने'; + break; + case 'y': + output = 'एक वर्ष'; + break; + case 'yy': + output = '%d वर्षे'; + break; + } + } else { + switch (string) { + case 's': + output = 'काही सेकंदां'; + break; + case 'ss': + output = '%d सेकंदां'; + break; + case 'm': + output = 'एका मिनिटा'; + break; + case 'mm': + output = '%d मिनिटां'; + break; + case 'h': + output = 'एका तासा'; + break; + case 'hh': + output = '%d तासां'; + break; + case 'd': + output = 'एका दिवसा'; + break; + case 'dd': + output = '%d दिवसां'; + break; + case 'M': + output = 'एका महिन्या'; + break; + case 'MM': + output = '%d महिन्यां'; + break; + case 'y': + output = 'एका वर्षा'; + break; + case 'yy': + output = '%d वर्षां'; + break; + } + } + return output.replace(/%d/i, number); + } + + hooks.defineLocale('mr', { + months: 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split( + '_' + ), + monthsShort: + 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'), + weekdaysShort: 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'), + weekdaysMin: 'र_सो_मं_बु_गु_शु_श'.split('_'), + longDateFormat: { + LT: 'A h:mm वाजता', + LTS: 'A h:mm:ss वाजता', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm वाजता', + LLLL: 'dddd, D MMMM YYYY, A h:mm वाजता', + }, + calendar: { + sameDay: '[आज] LT', + nextDay: '[उद्या] LT', + nextWeek: 'dddd, LT', + lastDay: '[काल] LT', + lastWeek: '[मागील] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%sमध्ये', + past: '%sपूर्वी', + s: relativeTimeMr, + ss: relativeTimeMr, + m: relativeTimeMr, + mm: relativeTimeMr, + h: relativeTimeMr, + hh: relativeTimeMr, + d: relativeTimeMr, + dd: relativeTimeMr, + M: relativeTimeMr, + MM: relativeTimeMr, + y: relativeTimeMr, + yy: relativeTimeMr, + }, + preparse: function (string) { + return string.replace(/[१२३४५६७८९०]/g, function (match) { + return numberMap$b[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$c[match]; + }); + }, + meridiemParse: /पहाटे|सकाळी|दुपारी|सायंकाळी|रात्री/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'पहाटे' || meridiem === 'सकाळी') { + return hour; + } else if ( + meridiem === 'दुपारी' || + meridiem === 'सायंकाळी' || + meridiem === 'रात्री' + ) { + return hour >= 12 ? hour : hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour >= 0 && hour < 6) { + return 'पहाटे'; + } else if (hour < 12) { + return 'सकाळी'; + } else if (hour < 17) { + return 'दुपारी'; + } else if (hour < 20) { + return 'सायंकाळी'; + } else { + return 'रात्री'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ms-my', { + months: 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'), + weekdays: 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'), + weekdaysShort: 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'), + weekdaysMin: 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'), + longDateFormat: { + LT: 'HH.mm', + LTS: 'HH.mm.ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY [pukul] HH.mm', + LLLL: 'dddd, D MMMM YYYY [pukul] HH.mm', + }, + meridiemParse: /pagi|tengahari|petang|malam/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'pagi') { + return hour; + } else if (meridiem === 'tengahari') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'petang' || meridiem === 'malam') { + return hour + 12; + } + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 11) { + return 'pagi'; + } else if (hours < 15) { + return 'tengahari'; + } else if (hours < 19) { + return 'petang'; + } else { + return 'malam'; + } + }, + calendar: { + sameDay: '[Hari ini pukul] LT', + nextDay: '[Esok pukul] LT', + nextWeek: 'dddd [pukul] LT', + lastDay: '[Kelmarin pukul] LT', + lastWeek: 'dddd [lepas pukul] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dalam %s', + past: '%s yang lepas', + s: 'beberapa saat', + ss: '%d saat', + m: 'seminit', + mm: '%d minit', + h: 'sejam', + hh: '%d jam', + d: 'sehari', + dd: '%d hari', + M: 'sebulan', + MM: '%d bulan', + y: 'setahun', + yy: '%d tahun', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ms', { + months: 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'), + weekdays: 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'), + weekdaysShort: 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'), + weekdaysMin: 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'), + longDateFormat: { + LT: 'HH.mm', + LTS: 'HH.mm.ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY [pukul] HH.mm', + LLLL: 'dddd, D MMMM YYYY [pukul] HH.mm', + }, + meridiemParse: /pagi|tengahari|petang|malam/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'pagi') { + return hour; + } else if (meridiem === 'tengahari') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'petang' || meridiem === 'malam') { + return hour + 12; + } + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 11) { + return 'pagi'; + } else if (hours < 15) { + return 'tengahari'; + } else if (hours < 19) { + return 'petang'; + } else { + return 'malam'; + } + }, + calendar: { + sameDay: '[Hari ini pukul] LT', + nextDay: '[Esok pukul] LT', + nextWeek: 'dddd [pukul] LT', + lastDay: '[Kelmarin pukul] LT', + lastWeek: 'dddd [lepas pukul] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dalam %s', + past: '%s yang lepas', + s: 'beberapa saat', + ss: '%d saat', + m: 'seminit', + mm: '%d minit', + h: 'sejam', + hh: '%d jam', + d: 'sehari', + dd: '%d hari', + M: 'sebulan', + MM: '%d bulan', + y: 'setahun', + yy: '%d tahun', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('mt', { + months: 'Jannar_Frar_Marzu_April_Mejju_Ġunju_Lulju_Awwissu_Settembru_Ottubru_Novembru_Diċembru'.split( + '_' + ), + monthsShort: 'Jan_Fra_Mar_Apr_Mej_Ġun_Lul_Aww_Set_Ott_Nov_Diċ'.split('_'), + weekdays: + 'Il-Ħadd_It-Tnejn_It-Tlieta_L-Erbgħa_Il-Ħamis_Il-Ġimgħa_Is-Sibt'.split( + '_' + ), + weekdaysShort: 'Ħad_Tne_Tli_Erb_Ħam_Ġim_Sib'.split('_'), + weekdaysMin: 'Ħa_Tn_Tl_Er_Ħa_Ġi_Si'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Illum fil-]LT', + nextDay: '[Għada fil-]LT', + nextWeek: 'dddd [fil-]LT', + lastDay: '[Il-bieraħ fil-]LT', + lastWeek: 'dddd [li għadda] [fil-]LT', + sameElse: 'L', + }, + relativeTime: { + future: 'f’ %s', + past: '%s ilu', + s: 'ftit sekondi', + ss: '%d sekondi', + m: 'minuta', + mm: '%d minuti', + h: 'siegħa', + hh: '%d siegħat', + d: 'ġurnata', + dd: '%d ġranet', + M: 'xahar', + MM: '%d xhur', + y: 'sena', + yy: '%d sni', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$d = { + 1: '၁', + 2: '၂', + 3: '၃', + 4: '၄', + 5: '၅', + 6: '၆', + 7: '၇', + 8: '၈', + 9: '၉', + 0: '၀', + }, + numberMap$c = { + '၁': '1', + '၂': '2', + '၃': '3', + '၄': '4', + '၅': '5', + '၆': '6', + '၇': '7', + '၈': '8', + '၉': '9', + '၀': '0', + }; + + hooks.defineLocale('my', { + months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split( + '_' + ), + monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'), + weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split( + '_' + ), + weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'), + weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'), + + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[ယနေ.] LT [မှာ]', + nextDay: '[မနက်ဖြန်] LT [မှာ]', + nextWeek: 'dddd LT [မှာ]', + lastDay: '[မနေ.က] LT [မှာ]', + lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]', + sameElse: 'L', + }, + relativeTime: { + future: 'လာမည့် %s မှာ', + past: 'လွန်ခဲ့သော %s က', + s: 'စက္ကန်.အနည်းငယ်', + ss: '%d စက္ကန့်', + m: 'တစ်မိနစ်', + mm: '%d မိနစ်', + h: 'တစ်နာရီ', + hh: '%d နာရီ', + d: 'တစ်ရက်', + dd: '%d ရက်', + M: 'တစ်လ', + MM: '%d လ', + y: 'တစ်နှစ်', + yy: '%d နှစ်', + }, + preparse: function (string) { + return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) { + return numberMap$c[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$d[match]; + }); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('nb', { + months: 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split( + '_' + ), + monthsShort: + 'jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.'.split('_'), + monthsParseExact: true, + weekdays: 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), + weekdaysShort: 'sø._ma._ti._on._to._fr._lø.'.split('_'), + weekdaysMin: 'sø_ma_ti_on_to_fr_lø'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY [kl.] HH:mm', + LLLL: 'dddd D. MMMM YYYY [kl.] HH:mm', + }, + calendar: { + sameDay: '[i dag kl.] LT', + nextDay: '[i morgen kl.] LT', + nextWeek: 'dddd [kl.] LT', + lastDay: '[i går kl.] LT', + lastWeek: '[forrige] dddd [kl.] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'om %s', + past: '%s siden', + s: 'noen sekunder', + ss: '%d sekunder', + m: 'ett minutt', + mm: '%d minutter', + h: 'en time', + hh: '%d timer', + d: 'en dag', + dd: '%d dager', + w: 'en uke', + ww: '%d uker', + M: 'en måned', + MM: '%d måneder', + y: 'ett år', + yy: '%d år', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$e = { + 1: '१', + 2: '२', + 3: '३', + 4: '४', + 5: '५', + 6: '६', + 7: '७', + 8: '८', + 9: '९', + 0: '०', + }, + numberMap$d = { + '१': '1', + '२': '2', + '३': '3', + '४': '4', + '५': '5', + '६': '6', + '७': '7', + '८': '8', + '९': '9', + '०': '0', + }; + + hooks.defineLocale('ne', { + months: 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split( + '_' + ), + monthsShort: + 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split( + '_' + ), + weekdaysShort: 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'), + weekdaysMin: 'आ._सो._मं._बु._बि._शु._श.'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'Aको h:mm बजे', + LTS: 'Aको h:mm:ss बजे', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, Aको h:mm बजे', + LLLL: 'dddd, D MMMM YYYY, Aको h:mm बजे', + }, + preparse: function (string) { + return string.replace(/[१२३४५६७८९०]/g, function (match) { + return numberMap$d[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$e[match]; + }); + }, + meridiemParse: /राति|बिहान|दिउँसो|साँझ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'राति') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'बिहान') { + return hour; + } else if (meridiem === 'दिउँसो') { + return hour >= 10 ? hour : hour + 12; + } else if (meridiem === 'साँझ') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 3) { + return 'राति'; + } else if (hour < 12) { + return 'बिहान'; + } else if (hour < 16) { + return 'दिउँसो'; + } else if (hour < 20) { + return 'साँझ'; + } else { + return 'राति'; + } + }, + calendar: { + sameDay: '[आज] LT', + nextDay: '[भोलि] LT', + nextWeek: '[आउँदो] dddd[,] LT', + lastDay: '[हिजो] LT', + lastWeek: '[गएको] dddd[,] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%sमा', + past: '%s अगाडि', + s: 'केही क्षण', + ss: '%d सेकेण्ड', + m: 'एक मिनेट', + mm: '%d मिनेट', + h: 'एक घण्टा', + hh: '%d घण्टा', + d: 'एक दिन', + dd: '%d दिन', + M: 'एक महिना', + MM: '%d महिना', + y: 'एक बर्ष', + yy: '%d बर्ष', + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsShortWithDots$1 = + 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'), + monthsShortWithoutDots$1 = + 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'), + monthsParse$8 = [ + /^jan/i, + /^feb/i, + /^maart|mrt.?$/i, + /^apr/i, + /^mei$/i, + /^jun[i.]?$/i, + /^jul[i.]?$/i, + /^aug/i, + /^sep/i, + /^okt/i, + /^nov/i, + /^dec/i, + ], + monthsRegex$8 = + /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; + + hooks.defineLocale('nl-be', { + months: 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortWithDots$1; + } else if (/-MMM-/.test(format)) { + return monthsShortWithoutDots$1[m.month()]; + } else { + return monthsShortWithDots$1[m.month()]; + } + }, + + monthsRegex: monthsRegex$8, + monthsShortRegex: monthsRegex$8, + monthsStrictRegex: + /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i, + monthsShortStrictRegex: + /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i, + + monthsParse: monthsParse$8, + longMonthsParse: monthsParse$8, + shortMonthsParse: monthsParse$8, + + weekdays: + 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'), + weekdaysShort: 'zo._ma._di._wo._do._vr._za.'.split('_'), + weekdaysMin: 'zo_ma_di_wo_do_vr_za'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[vandaag om] LT', + nextDay: '[morgen om] LT', + nextWeek: 'dddd [om] LT', + lastDay: '[gisteren om] LT', + lastWeek: '[afgelopen] dddd [om] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'over %s', + past: '%s geleden', + s: 'een paar seconden', + ss: '%d seconden', + m: 'één minuut', + mm: '%d minuten', + h: 'één uur', + hh: '%d uur', + d: 'één dag', + dd: '%d dagen', + M: 'één maand', + MM: '%d maanden', + y: 'één jaar', + yy: '%d jaar', + }, + dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/, + ordinal: function (number) { + return ( + number + + (number === 1 || number === 8 || number >= 20 ? 'ste' : 'de') + ); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsShortWithDots$2 = + 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'), + monthsShortWithoutDots$2 = + 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'), + monthsParse$9 = [ + /^jan/i, + /^feb/i, + /^maart|mrt.?$/i, + /^apr/i, + /^mei$/i, + /^jun[i.]?$/i, + /^jul[i.]?$/i, + /^aug/i, + /^sep/i, + /^okt/i, + /^nov/i, + /^dec/i, + ], + monthsRegex$9 = + /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; + + hooks.defineLocale('nl', { + months: 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split( + '_' + ), + monthsShort: function (m, format) { + if (!m) { + return monthsShortWithDots$2; + } else if (/-MMM-/.test(format)) { + return monthsShortWithoutDots$2[m.month()]; + } else { + return monthsShortWithDots$2[m.month()]; + } + }, + + monthsRegex: monthsRegex$9, + monthsShortRegex: monthsRegex$9, + monthsStrictRegex: + /^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i, + monthsShortStrictRegex: + /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i, + + monthsParse: monthsParse$9, + longMonthsParse: monthsParse$9, + shortMonthsParse: monthsParse$9, + + weekdays: + 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'), + weekdaysShort: 'zo._ma._di._wo._do._vr._za.'.split('_'), + weekdaysMin: 'zo_ma_di_wo_do_vr_za'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD-MM-YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[vandaag om] LT', + nextDay: '[morgen om] LT', + nextWeek: 'dddd [om] LT', + lastDay: '[gisteren om] LT', + lastWeek: '[afgelopen] dddd [om] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'over %s', + past: '%s geleden', + s: 'een paar seconden', + ss: '%d seconden', + m: 'één minuut', + mm: '%d minuten', + h: 'één uur', + hh: '%d uur', + d: 'één dag', + dd: '%d dagen', + w: 'één week', + ww: '%d weken', + M: 'één maand', + MM: '%d maanden', + y: 'één jaar', + yy: '%d jaar', + }, + dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/, + ordinal: function (number) { + return ( + number + + (number === 1 || number === 8 || number >= 20 ? 'ste' : 'de') + ); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('nn', { + months: 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split( + '_' + ), + monthsShort: + 'jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.'.split('_'), + monthsParseExact: true, + weekdays: 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'), + weekdaysShort: 'su._må._ty._on._to._fr._lau.'.split('_'), + weekdaysMin: 'su_må_ty_on_to_fr_la'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY [kl.] H:mm', + LLLL: 'dddd D. MMMM YYYY [kl.] HH:mm', + }, + calendar: { + sameDay: '[I dag klokka] LT', + nextDay: '[I morgon klokka] LT', + nextWeek: 'dddd [klokka] LT', + lastDay: '[I går klokka] LT', + lastWeek: '[Føregåande] dddd [klokka] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'om %s', + past: '%s sidan', + s: 'nokre sekund', + ss: '%d sekund', + m: 'eit minutt', + mm: '%d minutt', + h: 'ein time', + hh: '%d timar', + d: 'ein dag', + dd: '%d dagar', + w: 'ei veke', + ww: '%d veker', + M: 'ein månad', + MM: '%d månader', + y: 'eit år', + yy: '%d år', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('oc-lnc', { + months: { + standalone: + 'genièr_febrièr_març_abril_mai_junh_julhet_agost_setembre_octòbre_novembre_decembre'.split( + '_' + ), + format: "de genièr_de febrièr_de març_d'abril_de mai_de junh_de julhet_d'agost_de setembre_d'octòbre_de novembre_de decembre".split( + '_' + ), + isFormat: /D[oD]?(\s)+MMMM/, + }, + monthsShort: + 'gen._febr._març_abr._mai_junh_julh._ago._set._oct._nov._dec.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'dimenge_diluns_dimars_dimècres_dijòus_divendres_dissabte'.split( + '_' + ), + weekdaysShort: 'dg._dl._dm._dc._dj._dv._ds.'.split('_'), + weekdaysMin: 'dg_dl_dm_dc_dj_dv_ds'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM [de] YYYY', + ll: 'D MMM YYYY', + LLL: 'D MMMM [de] YYYY [a] H:mm', + lll: 'D MMM YYYY, H:mm', + LLLL: 'dddd D MMMM [de] YYYY [a] H:mm', + llll: 'ddd D MMM YYYY, H:mm', + }, + calendar: { + sameDay: '[uèi a] LT', + nextDay: '[deman a] LT', + nextWeek: 'dddd [a] LT', + lastDay: '[ièr a] LT', + lastWeek: 'dddd [passat a] LT', + sameElse: 'L', + }, + relativeTime: { + future: "d'aquí %s", + past: 'fa %s', + s: 'unas segondas', + ss: '%d segondas', + m: 'una minuta', + mm: '%d minutas', + h: 'una ora', + hh: '%d oras', + d: 'un jorn', + dd: '%d jorns', + M: 'un mes', + MM: '%d meses', + y: 'un an', + yy: '%d ans', + }, + dayOfMonthOrdinalParse: /\d{1,2}(r|n|t|è|a)/, + ordinal: function (number, period) { + var output = + number === 1 + ? 'r' + : number === 2 + ? 'n' + : number === 3 + ? 'r' + : number === 4 + ? 't' + : 'è'; + if (period === 'w' || period === 'W') { + output = 'a'; + } + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, + }, + }); + + //! moment.js locale configuration + + var symbolMap$f = { + 1: '੧', + 2: '੨', + 3: '੩', + 4: '੪', + 5: '੫', + 6: '੬', + 7: '੭', + 8: '੮', + 9: '੯', + 0: '੦', + }, + numberMap$e = { + '੧': '1', + '੨': '2', + '੩': '3', + '੪': '4', + '੫': '5', + '੬': '6', + '੭': '7', + '੮': '8', + '੯': '9', + '੦': '0', + }; + + hooks.defineLocale('pa-in', { + // There are months name as per Nanakshahi Calendar but they are not used as rigidly in modern Punjabi. + months: 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split( + '_' + ), + monthsShort: + 'ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ'.split( + '_' + ), + weekdays: 'ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ'.split( + '_' + ), + weekdaysShort: 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'), + weekdaysMin: 'ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ'.split('_'), + longDateFormat: { + LT: 'A h:mm ਵਜੇ', + LTS: 'A h:mm:ss ਵਜੇ', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm ਵਜੇ', + LLLL: 'dddd, D MMMM YYYY, A h:mm ਵਜੇ', + }, + calendar: { + sameDay: '[ਅਜ] LT', + nextDay: '[ਕਲ] LT', + nextWeek: '[ਅਗਲਾ] dddd, LT', + lastDay: '[ਕਲ] LT', + lastWeek: '[ਪਿਛਲੇ] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s ਵਿੱਚ', + past: '%s ਪਿਛਲੇ', + s: 'ਕੁਝ ਸਕਿੰਟ', + ss: '%d ਸਕਿੰਟ', + m: 'ਇਕ ਮਿੰਟ', + mm: '%d ਮਿੰਟ', + h: 'ਇੱਕ ਘੰਟਾ', + hh: '%d ਘੰਟੇ', + d: 'ਇੱਕ ਦਿਨ', + dd: '%d ਦਿਨ', + M: 'ਇੱਕ ਮਹੀਨਾ', + MM: '%d ਮਹੀਨੇ', + y: 'ਇੱਕ ਸਾਲ', + yy: '%d ਸਾਲ', + }, + preparse: function (string) { + return string.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (match) { + return numberMap$e[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$f[match]; + }); + }, + // Punjabi notation for meridiems are quite fuzzy in practice. While there exists + // a rigid notion of a 'Pahar' it is not used as rigidly in modern Punjabi. + meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'ਰਾਤ') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'ਸਵੇਰ') { + return hour; + } else if (meridiem === 'ਦੁਪਹਿਰ') { + return hour >= 10 ? hour : hour + 12; + } else if (meridiem === 'ਸ਼ਾਮ') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'ਰਾਤ'; + } else if (hour < 10) { + return 'ਸਵੇਰ'; + } else if (hour < 17) { + return 'ਦੁਪਹਿਰ'; + } else if (hour < 20) { + return 'ਸ਼ਾਮ'; + } else { + return 'ਰਾਤ'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var monthsNominative = + 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split( + '_' + ), + monthsSubjective = + 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split( + '_' + ), + monthsParse$a = [ + /^sty/i, + /^lut/i, + /^mar/i, + /^kwi/i, + /^maj/i, + /^cze/i, + /^lip/i, + /^sie/i, + /^wrz/i, + /^paź/i, + /^lis/i, + /^gru/i, + ]; + function plural$3(n) { + return n % 10 < 5 && n % 10 > 1 && ~~(n / 10) % 10 !== 1; + } + function translate$8(number, withoutSuffix, key) { + var result = number + ' '; + switch (key) { + case 'ss': + return result + (plural$3(number) ? 'sekundy' : 'sekund'); + case 'm': + return withoutSuffix ? 'minuta' : 'minutę'; + case 'mm': + return result + (plural$3(number) ? 'minuty' : 'minut'); + case 'h': + return withoutSuffix ? 'godzina' : 'godzinę'; + case 'hh': + return result + (plural$3(number) ? 'godziny' : 'godzin'); + case 'ww': + return result + (plural$3(number) ? 'tygodnie' : 'tygodni'); + case 'MM': + return result + (plural$3(number) ? 'miesiące' : 'miesięcy'); + case 'yy': + return result + (plural$3(number) ? 'lata' : 'lat'); + } + } + + hooks.defineLocale('pl', { + months: function (momentToFormat, format) { + if (!momentToFormat) { + return monthsNominative; + } else if (/D MMMM/.test(format)) { + return monthsSubjective[momentToFormat.month()]; + } else { + return monthsNominative[momentToFormat.month()]; + } + }, + monthsShort: 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'), + monthsParse: monthsParse$a, + longMonthsParse: monthsParse$a, + shortMonthsParse: monthsParse$a, + weekdays: + 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'), + weekdaysShort: 'ndz_pon_wt_śr_czw_pt_sob'.split('_'), + weekdaysMin: 'Nd_Pn_Wt_Śr_Cz_Pt_So'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Dziś o] LT', + nextDay: '[Jutro o] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[W niedzielę o] LT'; + + case 2: + return '[We wtorek o] LT'; + + case 3: + return '[W środę o] LT'; + + case 6: + return '[W sobotę o] LT'; + + default: + return '[W] dddd [o] LT'; + } + }, + lastDay: '[Wczoraj o] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[W zeszłą niedzielę o] LT'; + case 3: + return '[W zeszłą środę o] LT'; + case 6: + return '[W zeszłą sobotę o] LT'; + default: + return '[W zeszły] dddd [o] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: '%s temu', + s: 'kilka sekund', + ss: translate$8, + m: translate$8, + mm: translate$8, + h: translate$8, + hh: translate$8, + d: '1 dzień', + dd: '%d dni', + w: 'tydzień', + ww: translate$8, + M: 'miesiąc', + MM: translate$8, + y: 'rok', + yy: translate$8, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('pt-br', { + months: 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split( + '_' + ), + monthsShort: 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), + weekdays: + 'domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado'.split( + '_' + ), + weekdaysShort: 'dom_seg_ter_qua_qui_sex_sáb'.split('_'), + weekdaysMin: 'do_2ª_3ª_4ª_5ª_6ª_sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY [às] HH:mm', + LLLL: 'dddd, D [de] MMMM [de] YYYY [às] HH:mm', + }, + calendar: { + sameDay: '[Hoje às] LT', + nextDay: '[Amanhã às] LT', + nextWeek: 'dddd [às] LT', + lastDay: '[Ontem às] LT', + lastWeek: function () { + return this.day() === 0 || this.day() === 6 + ? '[Último] dddd [às] LT' // Saturday + Sunday + : '[Última] dddd [às] LT'; // Monday - Friday + }, + sameElse: 'L', + }, + relativeTime: { + future: 'em %s', + past: 'há %s', + s: 'poucos segundos', + ss: '%d segundos', + m: 'um minuto', + mm: '%d minutos', + h: 'uma hora', + hh: '%d horas', + d: 'um dia', + dd: '%d dias', + M: 'um mês', + MM: '%d meses', + y: 'um ano', + yy: '%d anos', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + invalidDate: 'Data inválida', + }); + + //! moment.js locale configuration + + hooks.defineLocale('pt', { + months: 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split( + '_' + ), + monthsShort: 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), + weekdays: + 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split( + '_' + ), + weekdaysShort: 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'), + weekdaysMin: 'Do_2ª_3ª_4ª_5ª_6ª_Sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D [de] MMMM [de] YYYY', + LLL: 'D [de] MMMM [de] YYYY HH:mm', + LLLL: 'dddd, D [de] MMMM [de] YYYY HH:mm', + }, + calendar: { + sameDay: '[Hoje às] LT', + nextDay: '[Amanhã às] LT', + nextWeek: 'dddd [às] LT', + lastDay: '[Ontem às] LT', + lastWeek: function () { + return this.day() === 0 || this.day() === 6 + ? '[Último] dddd [às] LT' // Saturday + Sunday + : '[Última] dddd [às] LT'; // Monday - Friday + }, + sameElse: 'L', + }, + relativeTime: { + future: 'em %s', + past: 'há %s', + s: 'segundos', + ss: '%d segundos', + m: 'um minuto', + mm: '%d minutos', + h: 'uma hora', + hh: '%d horas', + d: 'um dia', + dd: '%d dias', + w: 'uma semana', + ww: '%d semanas', + M: 'um mês', + MM: '%d meses', + y: 'um ano', + yy: '%d anos', + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal: '%dº', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function relativeTimeWithPlural$2(number, withoutSuffix, key) { + var format = { + ss: 'secunde', + mm: 'minute', + hh: 'ore', + dd: 'zile', + ww: 'săptămâni', + MM: 'luni', + yy: 'ani', + }, + separator = ' '; + if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) { + separator = ' de '; + } + return number + separator + format[key]; + } + + hooks.defineLocale('ro', { + months: 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split( + '_' + ), + monthsShort: + 'ian._feb._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'), + weekdaysShort: 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'), + weekdaysMin: 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY H:mm', + LLLL: 'dddd, D MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[azi la] LT', + nextDay: '[mâine la] LT', + nextWeek: 'dddd [la] LT', + lastDay: '[ieri la] LT', + lastWeek: '[fosta] dddd [la] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'peste %s', + past: '%s în urmă', + s: 'câteva secunde', + ss: relativeTimeWithPlural$2, + m: 'un minut', + mm: relativeTimeWithPlural$2, + h: 'o oră', + hh: relativeTimeWithPlural$2, + d: 'o zi', + dd: relativeTimeWithPlural$2, + w: 'o săptămână', + ww: relativeTimeWithPlural$2, + M: 'o lună', + MM: relativeTimeWithPlural$2, + y: 'un an', + yy: relativeTimeWithPlural$2, + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function plural$4(word, num) { + var forms = word.split('_'); + return num % 10 === 1 && num % 100 !== 11 + ? forms[0] + : num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) + ? forms[1] + : forms[2]; + } + function relativeTimeWithPlural$3(number, withoutSuffix, key) { + var format = { + ss: withoutSuffix ? 'секунда_секунды_секунд' : 'секунду_секунды_секунд', + mm: withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут', + hh: 'час_часа_часов', + dd: 'день_дня_дней', + ww: 'неделя_недели_недель', + MM: 'месяц_месяца_месяцев', + yy: 'год_года_лет', + }; + if (key === 'm') { + return withoutSuffix ? 'минута' : 'минуту'; + } else { + return number + ' ' + plural$4(format[key], +number); + } + } + var monthsParse$b = [ + /^янв/i, + /^фев/i, + /^мар/i, + /^апр/i, + /^ма[йя]/i, + /^июн/i, + /^июл/i, + /^авг/i, + /^сен/i, + /^окт/i, + /^ноя/i, + /^дек/i, + ]; + + // http://new.gramota.ru/spravka/rules/139-prop : § 103 + // Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637 + // CLDR data: http://www.unicode.org/cldr/charts/28/summary/ru.html#1753 + hooks.defineLocale('ru', { + months: { + format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split( + '_' + ), + standalone: + 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split( + '_' + ), + }, + monthsShort: { + // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку? + format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split( + '_' + ), + standalone: + 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split( + '_' + ), + }, + weekdays: { + standalone: + 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split( + '_' + ), + format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split( + '_' + ), + isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?] ?dddd/, + }, + weekdaysShort: 'вс_пн_вт_ср_чт_пт_сб'.split('_'), + weekdaysMin: 'вс_пн_вт_ср_чт_пт_сб'.split('_'), + monthsParse: monthsParse$b, + longMonthsParse: monthsParse$b, + shortMonthsParse: monthsParse$b, + + // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки + monthsRegex: + /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i, + + // копия предыдущего + monthsShortRegex: + /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i, + + // полные названия с падежами + monthsStrictRegex: + /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i, + + // Выражение, которое соответствует только сокращённым формам + monthsShortStrictRegex: + /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY г.', + LLL: 'D MMMM YYYY г., H:mm', + LLLL: 'dddd, D MMMM YYYY г., H:mm', + }, + calendar: { + sameDay: '[Сегодня, в] LT', + nextDay: '[Завтра, в] LT', + lastDay: '[Вчера, в] LT', + nextWeek: function (now) { + if (now.week() !== this.week()) { + switch (this.day()) { + case 0: + return '[В следующее] dddd, [в] LT'; + case 1: + case 2: + case 4: + return '[В следующий] dddd, [в] LT'; + case 3: + case 5: + case 6: + return '[В следующую] dddd, [в] LT'; + } + } else { + if (this.day() === 2) { + return '[Во] dddd, [в] LT'; + } else { + return '[В] dddd, [в] LT'; + } + } + }, + lastWeek: function (now) { + if (now.week() !== this.week()) { + switch (this.day()) { + case 0: + return '[В прошлое] dddd, [в] LT'; + case 1: + case 2: + case 4: + return '[В прошлый] dddd, [в] LT'; + case 3: + case 5: + case 6: + return '[В прошлую] dddd, [в] LT'; + } + } else { + if (this.day() === 2) { + return '[Во] dddd, [в] LT'; + } else { + return '[В] dddd, [в] LT'; + } + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'через %s', + past: '%s назад', + s: 'несколько секунд', + ss: relativeTimeWithPlural$3, + m: relativeTimeWithPlural$3, + mm: relativeTimeWithPlural$3, + h: 'час', + hh: relativeTimeWithPlural$3, + d: 'день', + dd: relativeTimeWithPlural$3, + w: 'неделя', + ww: relativeTimeWithPlural$3, + M: 'месяц', + MM: relativeTimeWithPlural$3, + y: 'год', + yy: relativeTimeWithPlural$3, + }, + meridiemParse: /ночи|утра|дня|вечера/i, + isPM: function (input) { + return /^(дня|вечера)$/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'ночи'; + } else if (hour < 12) { + return 'утра'; + } else if (hour < 17) { + return 'дня'; + } else { + return 'вечера'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}-(й|го|я)/, + ordinal: function (number, period) { + switch (period) { + case 'M': + case 'd': + case 'DDD': + return number + '-й'; + case 'D': + return number + '-го'; + case 'w': + case 'W': + return number + '-я'; + default: + return number; + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var months$9 = [ + 'جنوري', + 'فيبروري', + 'مارچ', + 'اپريل', + 'مئي', + 'جون', + 'جولاءِ', + 'آگسٽ', + 'سيپٽمبر', + 'آڪٽوبر', + 'نومبر', + 'ڊسمبر', + ], + days$1 = ['آچر', 'سومر', 'اڱارو', 'اربع', 'خميس', 'جمع', 'ڇنڇر']; + + hooks.defineLocale('sd', { + months: months$9, + monthsShort: months$9, + weekdays: days$1, + weekdaysShort: days$1, + weekdaysMin: days$1, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd، D MMMM YYYY HH:mm', + }, + meridiemParse: /صبح|شام/, + isPM: function (input) { + return 'شام' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'صبح'; + } + return 'شام'; + }, + calendar: { + sameDay: '[اڄ] LT', + nextDay: '[سڀاڻي] LT', + nextWeek: 'dddd [اڳين هفتي تي] LT', + lastDay: '[ڪالهه] LT', + lastWeek: '[گزريل هفتي] dddd [تي] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s پوء', + past: '%s اڳ', + s: 'چند سيڪنڊ', + ss: '%d سيڪنڊ', + m: 'هڪ منٽ', + mm: '%d منٽ', + h: 'هڪ ڪلاڪ', + hh: '%d ڪلاڪ', + d: 'هڪ ڏينهن', + dd: '%d ڏينهن', + M: 'هڪ مهينو', + MM: '%d مهينا', + y: 'هڪ سال', + yy: '%d سال', + }, + preparse: function (string) { + return string.replace(/،/g, ','); + }, + postformat: function (string) { + return string.replace(/,/g, '،'); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('se', { + months: 'ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu'.split( + '_' + ), + monthsShort: + 'ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov'.split('_'), + weekdays: + 'sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat'.split( + '_' + ), + weekdaysShort: 'sotn_vuos_maŋ_gask_duor_bear_láv'.split('_'), + weekdaysMin: 's_v_m_g_d_b_L'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'MMMM D. [b.] YYYY', + LLL: 'MMMM D. [b.] YYYY [ti.] HH:mm', + LLLL: 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm', + }, + calendar: { + sameDay: '[otne ti] LT', + nextDay: '[ihttin ti] LT', + nextWeek: 'dddd [ti] LT', + lastDay: '[ikte ti] LT', + lastWeek: '[ovddit] dddd [ti] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s geažes', + past: 'maŋit %s', + s: 'moadde sekunddat', + ss: '%d sekunddat', + m: 'okta minuhta', + mm: '%d minuhtat', + h: 'okta diimmu', + hh: '%d diimmut', + d: 'okta beaivi', + dd: '%d beaivvit', + M: 'okta mánnu', + MM: '%d mánut', + y: 'okta jahki', + yy: '%d jagit', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + /*jshint -W100*/ + hooks.defineLocale('si', { + months: 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split( + '_' + ), + monthsShort: 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split( + '_' + ), + weekdays: + 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split( + '_' + ), + weekdaysShort: 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'), + weekdaysMin: 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'a h:mm', + LTS: 'a h:mm:ss', + L: 'YYYY/MM/DD', + LL: 'YYYY MMMM D', + LLL: 'YYYY MMMM D, a h:mm', + LLLL: 'YYYY MMMM D [වැනි] dddd, a h:mm:ss', + }, + calendar: { + sameDay: '[අද] LT[ට]', + nextDay: '[හෙට] LT[ට]', + nextWeek: 'dddd LT[ට]', + lastDay: '[ඊයේ] LT[ට]', + lastWeek: '[පසුගිය] dddd LT[ට]', + sameElse: 'L', + }, + relativeTime: { + future: '%sකින්', + past: '%sකට පෙර', + s: 'තත්පර කිහිපය', + ss: 'තත්පර %d', + m: 'මිනිත්තුව', + mm: 'මිනිත්තු %d', + h: 'පැය', + hh: 'පැය %d', + d: 'දිනය', + dd: 'දින %d', + M: 'මාසය', + MM: 'මාස %d', + y: 'වසර', + yy: 'වසර %d', + }, + dayOfMonthOrdinalParse: /\d{1,2} වැනි/, + ordinal: function (number) { + return number + ' වැනි'; + }, + meridiemParse: /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./, + isPM: function (input) { + return input === 'ප.ව.' || input === 'පස් වරු'; + }, + meridiem: function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'ප.ව.' : 'පස් වරු'; + } else { + return isLower ? 'පෙ.ව.' : 'පෙර වරු'; + } + }, + }); + + //! moment.js locale configuration + + var months$a = + 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split( + '_' + ), + monthsShort$7 = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_'); + function plural$5(n) { + return n > 1 && n < 5; + } + function translate$9(number, withoutSuffix, key, isFuture) { + var result = number + ' '; + switch (key) { + case 's': // a few seconds / in a few seconds / a few seconds ago + return withoutSuffix || isFuture ? 'pár sekúnd' : 'pár sekundami'; + case 'ss': // 9 seconds / in 9 seconds / 9 seconds ago + if (withoutSuffix || isFuture) { + return result + (plural$5(number) ? 'sekundy' : 'sekúnd'); + } else { + return result + 'sekundami'; + } + case 'm': // a minute / in a minute / a minute ago + return withoutSuffix ? 'minúta' : isFuture ? 'minútu' : 'minútou'; + case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago + if (withoutSuffix || isFuture) { + return result + (plural$5(number) ? 'minúty' : 'minút'); + } else { + return result + 'minútami'; + } + case 'h': // an hour / in an hour / an hour ago + return withoutSuffix ? 'hodina' : isFuture ? 'hodinu' : 'hodinou'; + case 'hh': // 9 hours / in 9 hours / 9 hours ago + if (withoutSuffix || isFuture) { + return result + (plural$5(number) ? 'hodiny' : 'hodín'); + } else { + return result + 'hodinami'; + } + case 'd': // a day / in a day / a day ago + return withoutSuffix || isFuture ? 'deň' : 'dňom'; + case 'dd': // 9 days / in 9 days / 9 days ago + if (withoutSuffix || isFuture) { + return result + (plural$5(number) ? 'dni' : 'dní'); + } else { + return result + 'dňami'; + } + case 'M': // a month / in a month / a month ago + return withoutSuffix || isFuture ? 'mesiac' : 'mesiacom'; + case 'MM': // 9 months / in 9 months / 9 months ago + if (withoutSuffix || isFuture) { + return result + (plural$5(number) ? 'mesiace' : 'mesiacov'); + } else { + return result + 'mesiacmi'; + } + case 'y': // a year / in a year / a year ago + return withoutSuffix || isFuture ? 'rok' : 'rokom'; + case 'yy': // 9 years / in 9 years / 9 years ago + if (withoutSuffix || isFuture) { + return result + (plural$5(number) ? 'roky' : 'rokov'); + } else { + return result + 'rokmi'; + } + } + } + + hooks.defineLocale('sk', { + months: months$a, + monthsShort: monthsShort$7, + weekdays: 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'), + weekdaysShort: 'ne_po_ut_st_št_pi_so'.split('_'), + weekdaysMin: 'ne_po_ut_st_št_pi_so'.split('_'), + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm', + LLLL: 'dddd D. MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[dnes o] LT', + nextDay: '[zajtra o] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[v nedeľu o] LT'; + case 1: + case 2: + return '[v] dddd [o] LT'; + case 3: + return '[v stredu o] LT'; + case 4: + return '[vo štvrtok o] LT'; + case 5: + return '[v piatok o] LT'; + case 6: + return '[v sobotu o] LT'; + } + }, + lastDay: '[včera o] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[minulú nedeľu o] LT'; + case 1: + case 2: + return '[minulý] dddd [o] LT'; + case 3: + return '[minulú stredu o] LT'; + case 4: + case 5: + return '[minulý] dddd [o] LT'; + case 6: + return '[minulú sobotu o] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: 'pred %s', + s: translate$9, + ss: translate$9, + m: translate$9, + mm: translate$9, + h: translate$9, + hh: translate$9, + d: translate$9, + dd: translate$9, + M: translate$9, + MM: translate$9, + y: translate$9, + yy: translate$9, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function processRelativeTime$7(number, withoutSuffix, key, isFuture) { + var result = number + ' '; + switch (key) { + case 's': + return withoutSuffix || isFuture + ? 'nekaj sekund' + : 'nekaj sekundami'; + case 'ss': + if (number === 1) { + result += withoutSuffix ? 'sekundo' : 'sekundi'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'sekundi' : 'sekundah'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'sekunde' : 'sekundah'; + } else { + result += 'sekund'; + } + return result; + case 'm': + return withoutSuffix ? 'ena minuta' : 'eno minuto'; + case 'mm': + if (number === 1) { + result += withoutSuffix ? 'minuta' : 'minuto'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'minuti' : 'minutama'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'minute' : 'minutami'; + } else { + result += withoutSuffix || isFuture ? 'minut' : 'minutami'; + } + return result; + case 'h': + return withoutSuffix ? 'ena ura' : 'eno uro'; + case 'hh': + if (number === 1) { + result += withoutSuffix ? 'ura' : 'uro'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'uri' : 'urama'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'ure' : 'urami'; + } else { + result += withoutSuffix || isFuture ? 'ur' : 'urami'; + } + return result; + case 'd': + return withoutSuffix || isFuture ? 'en dan' : 'enim dnem'; + case 'dd': + if (number === 1) { + result += withoutSuffix || isFuture ? 'dan' : 'dnem'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'dni' : 'dnevoma'; + } else { + result += withoutSuffix || isFuture ? 'dni' : 'dnevi'; + } + return result; + case 'M': + return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem'; + case 'MM': + if (number === 1) { + result += withoutSuffix || isFuture ? 'mesec' : 'mesecem'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'meseca' : 'mesecema'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'mesece' : 'meseci'; + } else { + result += withoutSuffix || isFuture ? 'mesecev' : 'meseci'; + } + return result; + case 'y': + return withoutSuffix || isFuture ? 'eno leto' : 'enim letom'; + case 'yy': + if (number === 1) { + result += withoutSuffix || isFuture ? 'leto' : 'letom'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'leti' : 'letoma'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'leta' : 'leti'; + } else { + result += withoutSuffix || isFuture ? 'let' : 'leti'; + } + return result; + } + } + + hooks.defineLocale('sl', { + months: 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split( + '_' + ), + monthsShort: + 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'), + weekdaysShort: 'ned._pon._tor._sre._čet._pet._sob.'.split('_'), + weekdaysMin: 'ne_po_to_sr_če_pe_so'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD. MM. YYYY', + LL: 'D. MMMM YYYY', + LLL: 'D. MMMM YYYY H:mm', + LLLL: 'dddd, D. MMMM YYYY H:mm', + }, + calendar: { + sameDay: '[danes ob] LT', + nextDay: '[jutri ob] LT', + + nextWeek: function () { + switch (this.day()) { + case 0: + return '[v] [nedeljo] [ob] LT'; + case 3: + return '[v] [sredo] [ob] LT'; + case 6: + return '[v] [soboto] [ob] LT'; + case 1: + case 2: + case 4: + case 5: + return '[v] dddd [ob] LT'; + } + }, + lastDay: '[včeraj ob] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[prejšnjo] [nedeljo] [ob] LT'; + case 3: + return '[prejšnjo] [sredo] [ob] LT'; + case 6: + return '[prejšnjo] [soboto] [ob] LT'; + case 1: + case 2: + case 4: + case 5: + return '[prejšnji] dddd [ob] LT'; + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'čez %s', + past: 'pred %s', + s: processRelativeTime$7, + ss: processRelativeTime$7, + m: processRelativeTime$7, + mm: processRelativeTime$7, + h: processRelativeTime$7, + hh: processRelativeTime$7, + d: processRelativeTime$7, + dd: processRelativeTime$7, + M: processRelativeTime$7, + MM: processRelativeTime$7, + y: processRelativeTime$7, + yy: processRelativeTime$7, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('sq', { + months: 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split( + '_' + ), + monthsShort: 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'), + weekdays: 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split( + '_' + ), + weekdaysShort: 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'), + weekdaysMin: 'D_H_Ma_Më_E_P_Sh'.split('_'), + weekdaysParseExact: true, + meridiemParse: /PD|MD/, + isPM: function (input) { + return input.charAt(0) === 'M'; + }, + meridiem: function (hours, minutes, isLower) { + return hours < 12 ? 'PD' : 'MD'; + }, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Sot në] LT', + nextDay: '[Nesër në] LT', + nextWeek: 'dddd [në] LT', + lastDay: '[Dje në] LT', + lastWeek: 'dddd [e kaluar në] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'në %s', + past: '%s më parë', + s: 'disa sekonda', + ss: '%d sekonda', + m: 'një minutë', + mm: '%d minuta', + h: 'një orë', + hh: '%d orë', + d: 'një ditë', + dd: '%d ditë', + M: 'një muaj', + MM: '%d muaj', + y: 'një vit', + yy: '%d vite', + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var translator$1 = { + words: { + //Different grammatical cases + ss: ['секунда', 'секунде', 'секунди'], + m: ['један минут', 'једног минута'], + mm: ['минут', 'минута', 'минута'], + h: ['један сат', 'једног сата'], + hh: ['сат', 'сата', 'сати'], + d: ['један дан', 'једног дана'], + dd: ['дан', 'дана', 'дана'], + M: ['један месец', 'једног месеца'], + MM: ['месец', 'месеца', 'месеци'], + y: ['једну годину', 'једне године'], + yy: ['годину', 'године', 'година'], + }, + correctGrammaticalCase: function (number, wordKey) { + if ( + number % 10 >= 1 && + number % 10 <= 4 && + (number % 100 < 10 || number % 100 >= 20) + ) { + return number % 10 === 1 ? wordKey[0] : wordKey[1]; + } + return wordKey[2]; + }, + translate: function (number, withoutSuffix, key, isFuture) { + var wordKey = translator$1.words[key], + word; + + if (key.length === 1) { + // Nominativ + if (key === 'y' && withoutSuffix) return 'једна година'; + return isFuture || withoutSuffix ? wordKey[0] : wordKey[1]; + } + + word = translator$1.correctGrammaticalCase(number, wordKey); + // Nominativ + if (key === 'yy' && withoutSuffix && word === 'годину') { + return number + ' година'; + } + + return number + ' ' + word; + }, + }; + + hooks.defineLocale('sr-cyrl', { + months: 'јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар'.split( + '_' + ), + monthsShort: + 'јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.'.split('_'), + monthsParseExact: true, + weekdays: 'недеља_понедељак_уторак_среда_четвртак_петак_субота'.split('_'), + weekdaysShort: 'нед._пон._уто._сре._чет._пет._суб.'.split('_'), + weekdaysMin: 'не_по_ут_ср_че_пе_су'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'D. M. YYYY.', + LL: 'D. MMMM YYYY.', + LLL: 'D. MMMM YYYY. H:mm', + LLLL: 'dddd, D. MMMM YYYY. H:mm', + }, + calendar: { + sameDay: '[данас у] LT', + nextDay: '[сутра у] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[у] [недељу] [у] LT'; + case 3: + return '[у] [среду] [у] LT'; + case 6: + return '[у] [суботу] [у] LT'; + case 1: + case 2: + case 4: + case 5: + return '[у] dddd [у] LT'; + } + }, + lastDay: '[јуче у] LT', + lastWeek: function () { + var lastWeekDays = [ + '[прошле] [недеље] [у] LT', + '[прошлог] [понедељка] [у] LT', + '[прошлог] [уторка] [у] LT', + '[прошле] [среде] [у] LT', + '[прошлог] [четвртка] [у] LT', + '[прошлог] [петка] [у] LT', + '[прошле] [суботе] [у] LT', + ]; + return lastWeekDays[this.day()]; + }, + sameElse: 'L', + }, + relativeTime: { + future: 'за %s', + past: 'пре %s', + s: 'неколико секунди', + ss: translator$1.translate, + m: translator$1.translate, + mm: translator$1.translate, + h: translator$1.translate, + hh: translator$1.translate, + d: translator$1.translate, + dd: translator$1.translate, + M: translator$1.translate, + MM: translator$1.translate, + y: translator$1.translate, + yy: translator$1.translate, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 1st is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var translator$2 = { + words: { + //Different grammatical cases + ss: ['sekunda', 'sekunde', 'sekundi'], + m: ['jedan minut', 'jednog minuta'], + mm: ['minut', 'minuta', 'minuta'], + h: ['jedan sat', 'jednog sata'], + hh: ['sat', 'sata', 'sati'], + d: ['jedan dan', 'jednog dana'], + dd: ['dan', 'dana', 'dana'], + M: ['jedan mesec', 'jednog meseca'], + MM: ['mesec', 'meseca', 'meseci'], + y: ['jednu godinu', 'jedne godine'], + yy: ['godinu', 'godine', 'godina'], + }, + correctGrammaticalCase: function (number, wordKey) { + if ( + number % 10 >= 1 && + number % 10 <= 4 && + (number % 100 < 10 || number % 100 >= 20) + ) { + return number % 10 === 1 ? wordKey[0] : wordKey[1]; + } + return wordKey[2]; + }, + translate: function (number, withoutSuffix, key, isFuture) { + var wordKey = translator$2.words[key], + word; + + if (key.length === 1) { + // Nominativ + if (key === 'y' && withoutSuffix) return 'jedna godina'; + return isFuture || withoutSuffix ? wordKey[0] : wordKey[1]; + } + + word = translator$2.correctGrammaticalCase(number, wordKey); + // Nominativ + if (key === 'yy' && withoutSuffix && word === 'godinu') { + return number + ' godina'; + } + + return number + ' ' + word; + }, + }; + + hooks.defineLocale('sr', { + months: 'januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar'.split( + '_' + ), + monthsShort: + 'jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.'.split('_'), + monthsParseExact: true, + weekdays: 'nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota'.split( + '_' + ), + weekdaysShort: 'ned._pon._uto._sre._čet._pet._sub.'.split('_'), + weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'D. M. YYYY.', + LL: 'D. MMMM YYYY.', + LLL: 'D. MMMM YYYY. H:mm', + LLLL: 'dddd, D. MMMM YYYY. H:mm', + }, + calendar: { + sameDay: '[danas u] LT', + nextDay: '[sutra u] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[u] [nedelju] [u] LT'; + case 3: + return '[u] [sredu] [u] LT'; + case 6: + return '[u] [subotu] [u] LT'; + case 1: + case 2: + case 4: + case 5: + return '[u] dddd [u] LT'; + } + }, + lastDay: '[juče u] LT', + lastWeek: function () { + var lastWeekDays = [ + '[prošle] [nedelje] [u] LT', + '[prošlog] [ponedeljka] [u] LT', + '[prošlog] [utorka] [u] LT', + '[prošle] [srede] [u] LT', + '[prošlog] [četvrtka] [u] LT', + '[prošlog] [petka] [u] LT', + '[prošle] [subote] [u] LT', + ]; + return lastWeekDays[this.day()]; + }, + sameElse: 'L', + }, + relativeTime: { + future: 'za %s', + past: 'pre %s', + s: 'nekoliko sekundi', + ss: translator$2.translate, + m: translator$2.translate, + mm: translator$2.translate, + h: translator$2.translate, + hh: translator$2.translate, + d: translator$2.translate, + dd: translator$2.translate, + M: translator$2.translate, + MM: translator$2.translate, + y: translator$2.translate, + yy: translator$2.translate, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ss', { + months: "Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split( + '_' + ), + monthsShort: 'Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo'.split('_'), + weekdays: + 'Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo'.split( + '_' + ), + weekdaysShort: 'Lis_Umb_Lsb_Les_Lsi_Lsh_Umg'.split('_'), + weekdaysMin: 'Li_Us_Lb_Lt_Ls_Lh_Ug'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY h:mm A', + LLLL: 'dddd, D MMMM YYYY h:mm A', + }, + calendar: { + sameDay: '[Namuhla nga] LT', + nextDay: '[Kusasa nga] LT', + nextWeek: 'dddd [nga] LT', + lastDay: '[Itolo nga] LT', + lastWeek: 'dddd [leliphelile] [nga] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'nga %s', + past: 'wenteka nga %s', + s: 'emizuzwana lomcane', + ss: '%d mzuzwana', + m: 'umzuzu', + mm: '%d emizuzu', + h: 'lihora', + hh: '%d emahora', + d: 'lilanga', + dd: '%d emalanga', + M: 'inyanga', + MM: '%d tinyanga', + y: 'umnyaka', + yy: '%d iminyaka', + }, + meridiemParse: /ekuseni|emini|entsambama|ebusuku/, + meridiem: function (hours, minutes, isLower) { + if (hours < 11) { + return 'ekuseni'; + } else if (hours < 15) { + return 'emini'; + } else if (hours < 19) { + return 'entsambama'; + } else { + return 'ebusuku'; + } + }, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'ekuseni') { + return hour; + } else if (meridiem === 'emini') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'entsambama' || meridiem === 'ebusuku') { + if (hour === 0) { + return 0; + } + return hour + 12; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}/, + ordinal: '%d', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('sv', { + months: 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split( + '_' + ), + monthsShort: 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), + weekdays: 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'), + weekdaysShort: 'sön_mån_tis_ons_tor_fre_lör'.split('_'), + weekdaysMin: 'sö_må_ti_on_to_fr_lö'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY [kl.] HH:mm', + LLLL: 'dddd D MMMM YYYY [kl.] HH:mm', + lll: 'D MMM YYYY HH:mm', + llll: 'ddd D MMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Idag] LT', + nextDay: '[Imorgon] LT', + lastDay: '[Igår] LT', + nextWeek: '[På] dddd LT', + lastWeek: '[I] dddd[s] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'om %s', + past: 'för %s sedan', + s: 'några sekunder', + ss: '%d sekunder', + m: 'en minut', + mm: '%d minuter', + h: 'en timme', + hh: '%d timmar', + d: 'en dag', + dd: '%d dagar', + M: 'en månad', + MM: '%d månader', + y: 'ett år', + yy: '%d år', + }, + dayOfMonthOrdinalParse: /\d{1,2}(\:e|\:a)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? ':e' + : b === 1 + ? ':a' + : b === 2 + ? ':a' + : b === 3 + ? ':e' + : ':e'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('sw', { + months: 'Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba'.split( + '_' + ), + monthsShort: 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des'.split('_'), + weekdays: + 'Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi'.split( + '_' + ), + weekdaysShort: 'Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos'.split('_'), + weekdaysMin: 'J2_J3_J4_J5_Al_Ij_J1'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'hh:mm A', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[leo saa] LT', + nextDay: '[kesho saa] LT', + nextWeek: '[wiki ijayo] dddd [saat] LT', + lastDay: '[jana] LT', + lastWeek: '[wiki iliyopita] dddd [saat] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s baadaye', + past: 'tokea %s', + s: 'hivi punde', + ss: 'sekunde %d', + m: 'dakika moja', + mm: 'dakika %d', + h: 'saa limoja', + hh: 'masaa %d', + d: 'siku moja', + dd: 'siku %d', + M: 'mwezi mmoja', + MM: 'miezi %d', + y: 'mwaka mmoja', + yy: 'miaka %d', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var symbolMap$g = { + 1: '௧', + 2: '௨', + 3: '௩', + 4: '௪', + 5: '௫', + 6: '௬', + 7: '௭', + 8: '௮', + 9: '௯', + 0: '௦', + }, + numberMap$f = { + '௧': '1', + '௨': '2', + '௩': '3', + '௪': '4', + '௫': '5', + '௬': '6', + '௭': '7', + '௮': '8', + '௯': '9', + '௦': '0', + }; + + hooks.defineLocale('ta', { + months: 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split( + '_' + ), + monthsShort: + 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split( + '_' + ), + weekdays: + 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split( + '_' + ), + weekdaysShort: 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split( + '_' + ), + weekdaysMin: 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, HH:mm', + LLLL: 'dddd, D MMMM YYYY, HH:mm', + }, + calendar: { + sameDay: '[இன்று] LT', + nextDay: '[நாளை] LT', + nextWeek: 'dddd, LT', + lastDay: '[நேற்று] LT', + lastWeek: '[கடந்த வாரம்] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s இல்', + past: '%s முன்', + s: 'ஒரு சில விநாடிகள்', + ss: '%d விநாடிகள்', + m: 'ஒரு நிமிடம்', + mm: '%d நிமிடங்கள்', + h: 'ஒரு மணி நேரம்', + hh: '%d மணி நேரம்', + d: 'ஒரு நாள்', + dd: '%d நாட்கள்', + M: 'ஒரு மாதம்', + MM: '%d மாதங்கள்', + y: 'ஒரு வருடம்', + yy: '%d ஆண்டுகள்', + }, + dayOfMonthOrdinalParse: /\d{1,2}வது/, + ordinal: function (number) { + return number + 'வது'; + }, + preparse: function (string) { + return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) { + return numberMap$f[match]; + }); + }, + postformat: function (string) { + return string.replace(/\d/g, function (match) { + return symbolMap$g[match]; + }); + }, + // refer http://ta.wikipedia.org/s/1er1 + meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/, + meridiem: function (hour, minute, isLower) { + if (hour < 2) { + return ' யாமம்'; + } else if (hour < 6) { + return ' வைகறை'; // வைகறை + } else if (hour < 10) { + return ' காலை'; // காலை + } else if (hour < 14) { + return ' நண்பகல்'; // நண்பகல் + } else if (hour < 18) { + return ' எற்பாடு'; // எற்பாடு + } else if (hour < 22) { + return ' மாலை'; // மாலை + } else { + return ' யாமம்'; + } + }, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'யாமம்') { + return hour < 2 ? hour : hour + 12; + } else if (meridiem === 'வைகறை' || meridiem === 'காலை') { + return hour; + } else if (meridiem === 'நண்பகல்') { + return hour >= 10 ? hour : hour + 12; + } else { + return hour + 12; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('te', { + months: 'జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జులై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్'.split( + '_' + ), + monthsShort: + 'జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జులై_ఆగ._సెప్._అక్టో._నవ._డిసె.'.split( + '_' + ), + monthsParseExact: true, + weekdays: + 'ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం'.split( + '_' + ), + weekdaysShort: 'ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని'.split('_'), + weekdaysMin: 'ఆ_సో_మం_బు_గు_శు_శ'.split('_'), + longDateFormat: { + LT: 'A h:mm', + LTS: 'A h:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY, A h:mm', + LLLL: 'dddd, D MMMM YYYY, A h:mm', + }, + calendar: { + sameDay: '[నేడు] LT', + nextDay: '[రేపు] LT', + nextWeek: 'dddd, LT', + lastDay: '[నిన్న] LT', + lastWeek: '[గత] dddd, LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s లో', + past: '%s క్రితం', + s: 'కొన్ని క్షణాలు', + ss: '%d సెకన్లు', + m: 'ఒక నిమిషం', + mm: '%d నిమిషాలు', + h: 'ఒక గంట', + hh: '%d గంటలు', + d: 'ఒక రోజు', + dd: '%d రోజులు', + M: 'ఒక నెల', + MM: '%d నెలలు', + y: 'ఒక సంవత్సరం', + yy: '%d సంవత్సరాలు', + }, + dayOfMonthOrdinalParse: /\d{1,2}వ/, + ordinal: '%dవ', + meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'రాత్రి') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'ఉదయం') { + return hour; + } else if (meridiem === 'మధ్యాహ్నం') { + return hour >= 10 ? hour : hour + 12; + } else if (meridiem === 'సాయంత్రం') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'రాత్రి'; + } else if (hour < 10) { + return 'ఉదయం'; + } else if (hour < 17) { + return 'మధ్యాహ్నం'; + } else if (hour < 20) { + return 'సాయంత్రం'; + } else { + return 'రాత్రి'; + } + }, + week: { + dow: 0, // Sunday is the first day of the week. + doy: 6, // The week that contains Jan 6th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('tet', { + months: 'Janeiru_Fevereiru_Marsu_Abril_Maiu_Juñu_Jullu_Agustu_Setembru_Outubru_Novembru_Dezembru'.split( + '_' + ), + monthsShort: 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'), + weekdays: 'Domingu_Segunda_Tersa_Kuarta_Kinta_Sesta_Sabadu'.split('_'), + weekdaysShort: 'Dom_Seg_Ters_Kua_Kint_Sest_Sab'.split('_'), + weekdaysMin: 'Do_Seg_Te_Ku_Ki_Ses_Sa'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Ohin iha] LT', + nextDay: '[Aban iha] LT', + nextWeek: 'dddd [iha] LT', + lastDay: '[Horiseik iha] LT', + lastWeek: 'dddd [semana kotuk] [iha] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'iha %s', + past: '%s liuba', + s: 'segundu balun', + ss: 'segundu %d', + m: 'minutu ida', + mm: 'minutu %d', + h: 'oras ida', + hh: 'oras %d', + d: 'loron ida', + dd: 'loron %d', + M: 'fulan ida', + MM: 'fulan %d', + y: 'tinan ida', + yy: 'tinan %d', + }, + dayOfMonthOrdinalParse: /\d{1,2}(st|nd|rd|th)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var suffixes$3 = { + 0: '-ум', + 1: '-ум', + 2: '-юм', + 3: '-юм', + 4: '-ум', + 5: '-ум', + 6: '-ум', + 7: '-ум', + 8: '-ум', + 9: '-ум', + 10: '-ум', + 12: '-ум', + 13: '-ум', + 20: '-ум', + 30: '-юм', + 40: '-ум', + 50: '-ум', + 60: '-ум', + 70: '-ум', + 80: '-ум', + 90: '-ум', + 100: '-ум', + }; + + hooks.defineLocale('tg', { + months: { + format: 'январи_феврали_марти_апрели_майи_июни_июли_августи_сентябри_октябри_ноябри_декабри'.split( + '_' + ), + standalone: + 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split( + '_' + ), + }, + monthsShort: 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'), + weekdays: 'якшанбе_душанбе_сешанбе_чоршанбе_панҷшанбе_ҷумъа_шанбе'.split( + '_' + ), + weekdaysShort: 'яшб_дшб_сшб_чшб_пшб_ҷум_шнб'.split('_'), + weekdaysMin: 'яш_дш_сш_чш_пш_ҷм_шб'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Имрӯз соати] LT', + nextDay: '[Фардо соати] LT', + lastDay: '[Дирӯз соати] LT', + nextWeek: 'dddd[и] [ҳафтаи оянда соати] LT', + lastWeek: 'dddd[и] [ҳафтаи гузашта соати] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'баъди %s', + past: '%s пеш', + s: 'якчанд сония', + m: 'як дақиқа', + mm: '%d дақиқа', + h: 'як соат', + hh: '%d соат', + d: 'як рӯз', + dd: '%d рӯз', + M: 'як моҳ', + MM: '%d моҳ', + y: 'як сол', + yy: '%d сол', + }, + meridiemParse: /шаб|субҳ|рӯз|бегоҳ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'шаб') { + return hour < 4 ? hour : hour + 12; + } else if (meridiem === 'субҳ') { + return hour; + } else if (meridiem === 'рӯз') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'бегоҳ') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'шаб'; + } else if (hour < 11) { + return 'субҳ'; + } else if (hour < 16) { + return 'рӯз'; + } else if (hour < 19) { + return 'бегоҳ'; + } else { + return 'шаб'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}-(ум|юм)/, + ordinal: function (number) { + var a = number % 10, + b = number >= 100 ? 100 : null; + return number + (suffixes$3[number] || suffixes$3[a] || suffixes$3[b]); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 1th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('th', { + months: 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split( + '_' + ), + monthsShort: + 'ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'), + weekdaysShort: 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference + weekdaysMin: 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'H:mm', + LTS: 'H:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY เวลา H:mm', + LLLL: 'วันddddที่ D MMMM YYYY เวลา H:mm', + }, + meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/, + isPM: function (input) { + return input === 'หลังเที่ยง'; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'ก่อนเที่ยง'; + } else { + return 'หลังเที่ยง'; + } + }, + calendar: { + sameDay: '[วันนี้ เวลา] LT', + nextDay: '[พรุ่งนี้ เวลา] LT', + nextWeek: 'dddd[หน้า เวลา] LT', + lastDay: '[เมื่อวานนี้ เวลา] LT', + lastWeek: '[วัน]dddd[ที่แล้ว เวลา] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'อีก %s', + past: '%sที่แล้ว', + s: 'ไม่กี่วินาที', + ss: '%d วินาที', + m: '1 นาที', + mm: '%d นาที', + h: '1 ชั่วโมง', + hh: '%d ชั่วโมง', + d: '1 วัน', + dd: '%d วัน', + w: '1 สัปดาห์', + ww: '%d สัปดาห์', + M: '1 เดือน', + MM: '%d เดือน', + y: '1 ปี', + yy: '%d ปี', + }, + }); + + //! moment.js locale configuration + + var suffixes$4 = { + 1: "'inji", + 5: "'inji", + 8: "'inji", + 70: "'inji", + 80: "'inji", + 2: "'nji", + 7: "'nji", + 20: "'nji", + 50: "'nji", + 3: "'ünji", + 4: "'ünji", + 100: "'ünji", + 6: "'njy", + 9: "'unjy", + 10: "'unjy", + 30: "'unjy", + 60: "'ynjy", + 90: "'ynjy", + }; + + hooks.defineLocale('tk', { + months: 'Ýanwar_Fewral_Mart_Aprel_Maý_Iýun_Iýul_Awgust_Sentýabr_Oktýabr_Noýabr_Dekabr'.split( + '_' + ), + monthsShort: 'Ýan_Few_Mar_Apr_Maý_Iýn_Iýl_Awg_Sen_Okt_Noý_Dek'.split('_'), + weekdays: 'Ýekşenbe_Duşenbe_Sişenbe_Çarşenbe_Penşenbe_Anna_Şenbe'.split( + '_' + ), + weekdaysShort: 'Ýek_Duş_Siş_Çar_Pen_Ann_Şen'.split('_'), + weekdaysMin: 'Ýk_Dş_Sş_Çr_Pn_An_Şn'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[bugün sagat] LT', + nextDay: '[ertir sagat] LT', + nextWeek: '[indiki] dddd [sagat] LT', + lastDay: '[düýn] LT', + lastWeek: '[geçen] dddd [sagat] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s soň', + past: '%s öň', + s: 'birnäçe sekunt', + m: 'bir minut', + mm: '%d minut', + h: 'bir sagat', + hh: '%d sagat', + d: 'bir gün', + dd: '%d gün', + M: 'bir aý', + MM: '%d aý', + y: 'bir ýyl', + yy: '%d ýyl', + }, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'Do': + case 'DD': + return number; + default: + if (number === 0) { + // special case for zero + return number + "'unjy"; + } + var a = number % 10, + b = (number % 100) - a, + c = number >= 100 ? 100 : null; + return number + (suffixes$4[a] || suffixes$4[b] || suffixes$4[c]); + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('tl-ph', { + months: 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split( + '_' + ), + monthsShort: 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'), + weekdays: 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split( + '_' + ), + weekdaysShort: 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'), + weekdaysMin: 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'MM/D/YYYY', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY HH:mm', + LLLL: 'dddd, MMMM DD, YYYY HH:mm', + }, + calendar: { + sameDay: 'LT [ngayong araw]', + nextDay: '[Bukas ng] LT', + nextWeek: 'LT [sa susunod na] dddd', + lastDay: 'LT [kahapon]', + lastWeek: 'LT [noong nakaraang] dddd', + sameElse: 'L', + }, + relativeTime: { + future: 'sa loob ng %s', + past: '%s ang nakalipas', + s: 'ilang segundo', + ss: '%d segundo', + m: 'isang minuto', + mm: '%d minuto', + h: 'isang oras', + hh: '%d oras', + d: 'isang araw', + dd: '%d araw', + M: 'isang buwan', + MM: '%d buwan', + y: 'isang taon', + yy: '%d taon', + }, + dayOfMonthOrdinalParse: /\d{1,2}/, + ordinal: function (number) { + return number; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_'); + + function translateFuture(output) { + var time = output; + time = + output.indexOf('jaj') !== -1 + ? time.slice(0, -3) + 'leS' + : output.indexOf('jar') !== -1 + ? time.slice(0, -3) + 'waQ' + : output.indexOf('DIS') !== -1 + ? time.slice(0, -3) + 'nem' + : time + ' pIq'; + return time; + } + + function translatePast(output) { + var time = output; + time = + output.indexOf('jaj') !== -1 + ? time.slice(0, -3) + 'Hu’' + : output.indexOf('jar') !== -1 + ? time.slice(0, -3) + 'wen' + : output.indexOf('DIS') !== -1 + ? time.slice(0, -3) + 'ben' + : time + ' ret'; + return time; + } + + function translate$a(number, withoutSuffix, string, isFuture) { + var numberNoun = numberAsNoun(number); + switch (string) { + case 'ss': + return numberNoun + ' lup'; + case 'mm': + return numberNoun + ' tup'; + case 'hh': + return numberNoun + ' rep'; + case 'dd': + return numberNoun + ' jaj'; + case 'MM': + return numberNoun + ' jar'; + case 'yy': + return numberNoun + ' DIS'; + } + } + + function numberAsNoun(number) { + var hundred = Math.floor((number % 1000) / 100), + ten = Math.floor((number % 100) / 10), + one = number % 10, + word = ''; + if (hundred > 0) { + word += numbersNouns[hundred] + 'vatlh'; + } + if (ten > 0) { + word += (word !== '' ? ' ' : '') + numbersNouns[ten] + 'maH'; + } + if (one > 0) { + word += (word !== '' ? ' ' : '') + numbersNouns[one]; + } + return word === '' ? 'pagh' : word; + } + + hooks.defineLocale('tlh', { + months: 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split( + '_' + ), + monthsShort: + 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split( + '_' + ), + weekdaysShort: + 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'), + weekdaysMin: + 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[DaHjaj] LT', + nextDay: '[wa’leS] LT', + nextWeek: 'LLL', + lastDay: '[wa’Hu’] LT', + lastWeek: 'LLL', + sameElse: 'L', + }, + relativeTime: { + future: translateFuture, + past: translatePast, + s: 'puS lup', + ss: translate$a, + m: 'wa’ tup', + mm: translate$a, + h: 'wa’ rep', + hh: translate$a, + d: 'wa’ jaj', + dd: translate$a, + M: 'wa’ jar', + MM: translate$a, + y: 'wa’ DIS', + yy: translate$a, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var suffixes$5 = { + 1: "'inci", + 5: "'inci", + 8: "'inci", + 70: "'inci", + 80: "'inci", + 2: "'nci", + 7: "'nci", + 20: "'nci", + 50: "'nci", + 3: "'üncü", + 4: "'üncü", + 100: "'üncü", + 6: "'ncı", + 9: "'uncu", + 10: "'uncu", + 30: "'uncu", + 60: "'ıncı", + 90: "'ıncı", + }; + + hooks.defineLocale('tr', { + months: 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split( + '_' + ), + monthsShort: 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'), + weekdays: 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split( + '_' + ), + weekdaysShort: 'Paz_Pzt_Sal_Çar_Per_Cum_Cmt'.split('_'), + weekdaysMin: 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'), + meridiem: function (hours, minutes, isLower) { + if (hours < 12) { + return isLower ? 'öö' : 'ÖÖ'; + } else { + return isLower ? 'ös' : 'ÖS'; + } + }, + meridiemParse: /öö|ÖÖ|ös|ÖS/, + isPM: function (input) { + return input === 'ös' || input === 'ÖS'; + }, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[bugün saat] LT', + nextDay: '[yarın saat] LT', + nextWeek: '[gelecek] dddd [saat] LT', + lastDay: '[dün] LT', + lastWeek: '[geçen] dddd [saat] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s sonra', + past: '%s önce', + s: 'birkaç saniye', + ss: '%d saniye', + m: 'bir dakika', + mm: '%d dakika', + h: 'bir saat', + hh: '%d saat', + d: 'bir gün', + dd: '%d gün', + w: 'bir hafta', + ww: '%d hafta', + M: 'bir ay', + MM: '%d ay', + y: 'bir yıl', + yy: '%d yıl', + }, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'Do': + case 'DD': + return number; + default: + if (number === 0) { + // special case for zero + return number + "'ıncı"; + } + var a = number % 10, + b = (number % 100) - a, + c = number >= 100 ? 100 : null; + return number + (suffixes$5[a] || suffixes$5[b] || suffixes$5[c]); + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + // After the year there should be a slash and the amount of years since December 26, 1979 in Roman numerals. + // This is currently too difficult (maybe even impossible) to add. + hooks.defineLocale('tzl', { + months: 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split( + '_' + ), + monthsShort: 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'), + weekdays: 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'), + weekdaysShort: 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'), + weekdaysMin: 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'), + longDateFormat: { + LT: 'HH.mm', + LTS: 'HH.mm.ss', + L: 'DD.MM.YYYY', + LL: 'D. MMMM [dallas] YYYY', + LLL: 'D. MMMM [dallas] YYYY HH.mm', + LLLL: 'dddd, [li] D. MMMM [dallas] YYYY HH.mm', + }, + meridiemParse: /d\'o|d\'a/i, + isPM: function (input) { + return "d'o" === input.toLowerCase(); + }, + meridiem: function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? "d'o" : "D'O"; + } else { + return isLower ? "d'a" : "D'A"; + } + }, + calendar: { + sameDay: '[oxhi à] LT', + nextDay: '[demà à] LT', + nextWeek: 'dddd [à] LT', + lastDay: '[ieiri à] LT', + lastWeek: '[sür el] dddd [lasteu à] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'osprei %s', + past: 'ja%s', + s: processRelativeTime$8, + ss: processRelativeTime$8, + m: processRelativeTime$8, + mm: processRelativeTime$8, + h: processRelativeTime$8, + hh: processRelativeTime$8, + d: processRelativeTime$8, + dd: processRelativeTime$8, + M: processRelativeTime$8, + MM: processRelativeTime$8, + y: processRelativeTime$8, + yy: processRelativeTime$8, + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal: '%d.', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + function processRelativeTime$8(number, withoutSuffix, key, isFuture) { + var format = { + s: ['viensas secunds', "'iensas secunds"], + ss: [number + ' secunds', '' + number + ' secunds'], + m: ["'n míut", "'iens míut"], + mm: [number + ' míuts', '' + number + ' míuts'], + h: ["'n þora", "'iensa þora"], + hh: [number + ' þoras', '' + number + ' þoras'], + d: ["'n ziua", "'iensa ziua"], + dd: [number + ' ziuas', '' + number + ' ziuas'], + M: ["'n mes", "'iens mes"], + MM: [number + ' mesen', '' + number + ' mesen'], + y: ["'n ar", "'iens ar"], + yy: [number + ' ars', '' + number + ' ars'], + }; + return isFuture + ? format[key][0] + : withoutSuffix + ? format[key][0] + : format[key][1]; + } + + //! moment.js locale configuration + + hooks.defineLocale('tzm-latn', { + months: 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split( + '_' + ), + monthsShort: + 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split( + '_' + ), + weekdays: 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), + weekdaysShort: 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), + weekdaysMin: 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[asdkh g] LT', + nextDay: '[aska g] LT', + nextWeek: 'dddd [g] LT', + lastDay: '[assant g] LT', + lastWeek: 'dddd [g] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'dadkh s yan %s', + past: 'yan %s', + s: 'imik', + ss: '%d imik', + m: 'minuḍ', + mm: '%d minuḍ', + h: 'saɛa', + hh: '%d tassaɛin', + d: 'ass', + dd: '%d ossan', + M: 'ayowr', + MM: '%d iyyirn', + y: 'asgas', + yy: '%d isgasn', + }, + week: { + dow: 6, // Saturday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('tzm', { + months: 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split( + '_' + ), + monthsShort: + 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split( + '_' + ), + weekdays: 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), + weekdaysShort: 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), + weekdaysMin: 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[ⴰⵙⴷⵅ ⴴ] LT', + nextDay: '[ⴰⵙⴽⴰ ⴴ] LT', + nextWeek: 'dddd [ⴴ] LT', + lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT', + lastWeek: 'dddd [ⴴ] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s', + past: 'ⵢⴰⵏ %s', + s: 'ⵉⵎⵉⴽ', + ss: '%d ⵉⵎⵉⴽ', + m: 'ⵎⵉⵏⵓⴺ', + mm: '%d ⵎⵉⵏⵓⴺ', + h: 'ⵙⴰⵄⴰ', + hh: '%d ⵜⴰⵙⵙⴰⵄⵉⵏ', + d: 'ⴰⵙⵙ', + dd: '%d oⵙⵙⴰⵏ', + M: 'ⴰⵢoⵓⵔ', + MM: '%d ⵉⵢⵢⵉⵔⵏ', + y: 'ⴰⵙⴳⴰⵙ', + yy: '%d ⵉⵙⴳⴰⵙⵏ', + }, + week: { + dow: 6, // Saturday is the first day of the week. + doy: 12, // The week that contains Jan 12th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('ug-cn', { + months: 'يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر'.split( + '_' + ), + monthsShort: + 'يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر'.split( + '_' + ), + weekdays: 'يەكشەنبە_دۈشەنبە_سەيشەنبە_چارشەنبە_پەيشەنبە_جۈمە_شەنبە'.split( + '_' + ), + weekdaysShort: 'يە_دۈ_سە_چا_پە_جۈ_شە'.split('_'), + weekdaysMin: 'يە_دۈ_سە_چا_پە_جۈ_شە'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY-MM-DD', + LL: 'YYYY-يىلىM-ئاينىڭD-كۈنى', + LLL: 'YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm', + LLLL: 'dddd، YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm', + }, + meridiemParse: /يېرىم كېچە|سەھەر|چۈشتىن بۇرۇن|چۈش|چۈشتىن كېيىن|كەچ/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if ( + meridiem === 'يېرىم كېچە' || + meridiem === 'سەھەر' || + meridiem === 'چۈشتىن بۇرۇن' + ) { + return hour; + } else if (meridiem === 'چۈشتىن كېيىن' || meridiem === 'كەچ') { + return hour + 12; + } else { + return hour >= 11 ? hour : hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + var hm = hour * 100 + minute; + if (hm < 600) { + return 'يېرىم كېچە'; + } else if (hm < 900) { + return 'سەھەر'; + } else if (hm < 1130) { + return 'چۈشتىن بۇرۇن'; + } else if (hm < 1230) { + return 'چۈش'; + } else if (hm < 1800) { + return 'چۈشتىن كېيىن'; + } else { + return 'كەچ'; + } + }, + calendar: { + sameDay: '[بۈگۈن سائەت] LT', + nextDay: '[ئەتە سائەت] LT', + nextWeek: '[كېلەركى] dddd [سائەت] LT', + lastDay: '[تۆنۈگۈن] LT', + lastWeek: '[ئالدىنقى] dddd [سائەت] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s كېيىن', + past: '%s بۇرۇن', + s: 'نەچچە سېكونت', + ss: '%d سېكونت', + m: 'بىر مىنۇت', + mm: '%d مىنۇت', + h: 'بىر سائەت', + hh: '%d سائەت', + d: 'بىر كۈن', + dd: '%d كۈن', + M: 'بىر ئاي', + MM: '%d ئاي', + y: 'بىر يىل', + yy: '%d يىل', + }, + + dayOfMonthOrdinalParse: /\d{1,2}(-كۈنى|-ئاي|-ھەپتە)/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + '-كۈنى'; + case 'w': + case 'W': + return number + '-ھەپتە'; + default: + return number; + } + }, + preparse: function (string) { + return string.replace(/،/g, ','); + }, + postformat: function (string) { + return string.replace(/,/g, '،'); + }, + week: { + // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 1st is the first week of the year. + }, + }); + + //! moment.js locale configuration + + function plural$6(word, num) { + var forms = word.split('_'); + return num % 10 === 1 && num % 100 !== 11 + ? forms[0] + : num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) + ? forms[1] + : forms[2]; + } + function relativeTimeWithPlural$4(number, withoutSuffix, key) { + var format = { + ss: withoutSuffix ? 'секунда_секунди_секунд' : 'секунду_секунди_секунд', + mm: withoutSuffix ? 'хвилина_хвилини_хвилин' : 'хвилину_хвилини_хвилин', + hh: withoutSuffix ? 'година_години_годин' : 'годину_години_годин', + dd: 'день_дні_днів', + MM: 'місяць_місяці_місяців', + yy: 'рік_роки_років', + }; + if (key === 'm') { + return withoutSuffix ? 'хвилина' : 'хвилину'; + } else if (key === 'h') { + return withoutSuffix ? 'година' : 'годину'; + } else { + return number + ' ' + plural$6(format[key], +number); + } + } + function weekdaysCaseReplace(m, format) { + var weekdays = { + nominative: + 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split( + '_' + ), + accusative: + 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split( + '_' + ), + genitive: + 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split( + '_' + ), + }, + nounCase; + + if (m === true) { + return weekdays['nominative'] + .slice(1, 7) + .concat(weekdays['nominative'].slice(0, 1)); + } + if (!m) { + return weekdays['nominative']; + } + + nounCase = /(\[[ВвУу]\]) ?dddd/.test(format) + ? 'accusative' + : /\[?(?:минулої|наступної)? ?\] ?dddd/.test(format) + ? 'genitive' + : 'nominative'; + return weekdays[nounCase][m.day()]; + } + function processHoursFunction(str) { + return function () { + return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT'; + }; + } + + hooks.defineLocale('uk', { + months: { + format: 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split( + '_' + ), + standalone: + 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split( + '_' + ), + }, + monthsShort: 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split( + '_' + ), + weekdays: weekdaysCaseReplace, + weekdaysShort: 'нд_пн_вт_ср_чт_пт_сб'.split('_'), + weekdaysMin: 'нд_пн_вт_ср_чт_пт_сб'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD.MM.YYYY', + LL: 'D MMMM YYYY р.', + LLL: 'D MMMM YYYY р., HH:mm', + LLLL: 'dddd, D MMMM YYYY р., HH:mm', + }, + calendar: { + sameDay: processHoursFunction('[Сьогодні '), + nextDay: processHoursFunction('[Завтра '), + lastDay: processHoursFunction('[Вчора '), + nextWeek: processHoursFunction('[У] dddd ['), + lastWeek: function () { + switch (this.day()) { + case 0: + case 3: + case 5: + case 6: + return processHoursFunction('[Минулої] dddd [').call(this); + case 1: + case 2: + case 4: + return processHoursFunction('[Минулого] dddd [').call(this); + } + }, + sameElse: 'L', + }, + relativeTime: { + future: 'за %s', + past: '%s тому', + s: 'декілька секунд', + ss: relativeTimeWithPlural$4, + m: relativeTimeWithPlural$4, + mm: relativeTimeWithPlural$4, + h: 'годину', + hh: relativeTimeWithPlural$4, + d: 'день', + dd: relativeTimeWithPlural$4, + M: 'місяць', + MM: relativeTimeWithPlural$4, + y: 'рік', + yy: relativeTimeWithPlural$4, + }, + // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason + meridiemParse: /ночі|ранку|дня|вечора/, + isPM: function (input) { + return /^(дня|вечора)$/.test(input); + }, + meridiem: function (hour, minute, isLower) { + if (hour < 4) { + return 'ночі'; + } else if (hour < 12) { + return 'ранку'; + } else if (hour < 17) { + return 'дня'; + } else { + return 'вечора'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}-(й|го)/, + ordinal: function (number, period) { + switch (period) { + case 'M': + case 'd': + case 'DDD': + case 'w': + case 'W': + return number + '-й'; + case 'D': + return number + '-го'; + default: + return number; + } + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + var months$b = [ + 'جنوری', + 'فروری', + 'مارچ', + 'اپریل', + 'مئی', + 'جون', + 'جولائی', + 'اگست', + 'ستمبر', + 'اکتوبر', + 'نومبر', + 'دسمبر', + ], + days$2 = ['اتوار', 'پیر', 'منگل', 'بدھ', 'جمعرات', 'جمعہ', 'ہفتہ']; + + hooks.defineLocale('ur', { + months: months$b, + monthsShort: months$b, + weekdays: days$2, + weekdaysShort: days$2, + weekdaysMin: days$2, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd، D MMMM YYYY HH:mm', + }, + meridiemParse: /صبح|شام/, + isPM: function (input) { + return 'شام' === input; + }, + meridiem: function (hour, minute, isLower) { + if (hour < 12) { + return 'صبح'; + } + return 'شام'; + }, + calendar: { + sameDay: '[آج بوقت] LT', + nextDay: '[کل بوقت] LT', + nextWeek: 'dddd [بوقت] LT', + lastDay: '[گذشتہ روز بوقت] LT', + lastWeek: '[گذشتہ] dddd [بوقت] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s بعد', + past: '%s قبل', + s: 'چند سیکنڈ', + ss: '%d سیکنڈ', + m: 'ایک منٹ', + mm: '%d منٹ', + h: 'ایک گھنٹہ', + hh: '%d گھنٹے', + d: 'ایک دن', + dd: '%d دن', + M: 'ایک ماہ', + MM: '%d ماہ', + y: 'ایک سال', + yy: '%d سال', + }, + preparse: function (string) { + return string.replace(/،/g, ','); + }, + postformat: function (string) { + return string.replace(/,/g, '،'); + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('uz-latn', { + months: 'Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr'.split( + '_' + ), + monthsShort: 'Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek'.split('_'), + weekdays: + 'Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba'.split( + '_' + ), + weekdaysShort: 'Yak_Dush_Sesh_Chor_Pay_Jum_Shan'.split('_'), + weekdaysMin: 'Ya_Du_Se_Cho_Pa_Ju_Sha'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'D MMMM YYYY, dddd HH:mm', + }, + calendar: { + sameDay: '[Bugun soat] LT [da]', + nextDay: '[Ertaga] LT [da]', + nextWeek: 'dddd [kuni soat] LT [da]', + lastDay: '[Kecha soat] LT [da]', + lastWeek: "[O'tgan] dddd [kuni soat] LT [da]", + sameElse: 'L', + }, + relativeTime: { + future: 'Yaqin %s ichida', + past: 'Bir necha %s oldin', + s: 'soniya', + ss: '%d soniya', + m: 'bir daqiqa', + mm: '%d daqiqa', + h: 'bir soat', + hh: '%d soat', + d: 'bir kun', + dd: '%d kun', + M: 'bir oy', + MM: '%d oy', + y: 'bir yil', + yy: '%d yil', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 7th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('uz', { + months: 'январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр'.split( + '_' + ), + monthsShort: 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'), + weekdays: 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'), + weekdaysShort: 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'), + weekdaysMin: 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'D MMMM YYYY, dddd HH:mm', + }, + calendar: { + sameDay: '[Бугун соат] LT [да]', + nextDay: '[Эртага] LT [да]', + nextWeek: 'dddd [куни соат] LT [да]', + lastDay: '[Кеча соат] LT [да]', + lastWeek: '[Утган] dddd [куни соат] LT [да]', + sameElse: 'L', + }, + relativeTime: { + future: 'Якин %s ичида', + past: 'Бир неча %s олдин', + s: 'фурсат', + ss: '%d фурсат', + m: 'бир дакика', + mm: '%d дакика', + h: 'бир соат', + hh: '%d соат', + d: 'бир кун', + dd: '%d кун', + M: 'бир ой', + MM: '%d ой', + y: 'бир йил', + yy: '%d йил', + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 7, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('vi', { + months: 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split( + '_' + ), + monthsShort: + 'Thg 01_Thg 02_Thg 03_Thg 04_Thg 05_Thg 06_Thg 07_Thg 08_Thg 09_Thg 10_Thg 11_Thg 12'.split( + '_' + ), + monthsParseExact: true, + weekdays: 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split( + '_' + ), + weekdaysShort: 'CN_T2_T3_T4_T5_T6_T7'.split('_'), + weekdaysMin: 'CN_T2_T3_T4_T5_T6_T7'.split('_'), + weekdaysParseExact: true, + meridiemParse: /sa|ch/i, + isPM: function (input) { + return /^ch$/i.test(input); + }, + meridiem: function (hours, minutes, isLower) { + if (hours < 12) { + return isLower ? 'sa' : 'SA'; + } else { + return isLower ? 'ch' : 'CH'; + } + }, + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'D MMMM [năm] YYYY', + LLL: 'D MMMM [năm] YYYY HH:mm', + LLLL: 'dddd, D MMMM [năm] YYYY HH:mm', + l: 'DD/M/YYYY', + ll: 'D MMM YYYY', + lll: 'D MMM YYYY HH:mm', + llll: 'ddd, D MMM YYYY HH:mm', + }, + calendar: { + sameDay: '[Hôm nay lúc] LT', + nextDay: '[Ngày mai lúc] LT', + nextWeek: 'dddd [tuần tới lúc] LT', + lastDay: '[Hôm qua lúc] LT', + lastWeek: 'dddd [tuần trước lúc] LT', + sameElse: 'L', + }, + relativeTime: { + future: '%s tới', + past: '%s trước', + s: 'vài giây', + ss: '%d giây', + m: 'một phút', + mm: '%d phút', + h: 'một giờ', + hh: '%d giờ', + d: 'một ngày', + dd: '%d ngày', + w: 'một tuần', + ww: '%d tuần', + M: 'một tháng', + MM: '%d tháng', + y: 'một năm', + yy: '%d năm', + }, + dayOfMonthOrdinalParse: /\d{1,2}/, + ordinal: function (number) { + return number; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('x-pseudo', { + months: 'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split( + '_' + ), + monthsShort: + 'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split( + '_' + ), + monthsParseExact: true, + weekdays: + 'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split( + '_' + ), + weekdaysShort: 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'), + weekdaysMin: 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'), + weekdaysParseExact: true, + longDateFormat: { + LT: 'HH:mm', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY HH:mm', + LLLL: 'dddd, D MMMM YYYY HH:mm', + }, + calendar: { + sameDay: '[T~ódá~ý át] LT', + nextDay: '[T~ómó~rró~w át] LT', + nextWeek: 'dddd [át] LT', + lastDay: '[Ý~ést~érdá~ý át] LT', + lastWeek: '[L~ást] dddd [át] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'í~ñ %s', + past: '%s á~gó', + s: 'á ~féw ~sécó~ñds', + ss: '%d s~écóñ~ds', + m: 'á ~míñ~úté', + mm: '%d m~íñú~tés', + h: 'á~ñ hó~úr', + hh: '%d h~óúrs', + d: 'á ~dáý', + dd: '%d d~áýs', + M: 'á ~móñ~th', + MM: '%d m~óñt~hs', + y: 'á ~ýéár', + yy: '%d ý~éárs', + }, + dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal: function (number) { + var b = number % 10, + output = + ~~((number % 100) / 10) === 1 + ? 'th' + : b === 1 + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; + return number + output; + }, + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('yo', { + months: 'Sẹ́rẹ́_Èrèlè_Ẹrẹ̀nà_Ìgbé_Èbibi_Òkùdu_Agẹmo_Ògún_Owewe_Ọ̀wàrà_Bélú_Ọ̀pẹ̀̀'.split( + '_' + ), + monthsShort: 'Sẹ́r_Èrl_Ẹrn_Ìgb_Èbi_Òkù_Agẹ_Ògú_Owe_Ọ̀wà_Bél_Ọ̀pẹ̀̀'.split('_'), + weekdays: 'Àìkú_Ajé_Ìsẹ́gun_Ọjọ́rú_Ọjọ́bọ_Ẹtì_Àbámẹ́ta'.split('_'), + weekdaysShort: 'Àìk_Ajé_Ìsẹ́_Ọjr_Ọjb_Ẹtì_Àbá'.split('_'), + weekdaysMin: 'Àì_Aj_Ìs_Ọr_Ọb_Ẹt_Àb'.split('_'), + longDateFormat: { + LT: 'h:mm A', + LTS: 'h:mm:ss A', + L: 'DD/MM/YYYY', + LL: 'D MMMM YYYY', + LLL: 'D MMMM YYYY h:mm A', + LLLL: 'dddd, D MMMM YYYY h:mm A', + }, + calendar: { + sameDay: '[Ònì ni] LT', + nextDay: '[Ọ̀la ni] LT', + nextWeek: "dddd [Ọsẹ̀ tón'bọ] [ni] LT", + lastDay: '[Àna ni] LT', + lastWeek: 'dddd [Ọsẹ̀ tólọ́] [ni] LT', + sameElse: 'L', + }, + relativeTime: { + future: 'ní %s', + past: '%s kọjá', + s: 'ìsẹjú aayá die', + ss: 'aayá %d', + m: 'ìsẹjú kan', + mm: 'ìsẹjú %d', + h: 'wákati kan', + hh: 'wákati %d', + d: 'ọjọ́ kan', + dd: 'ọjọ́ %d', + M: 'osù kan', + MM: 'osù %d', + y: 'ọdún kan', + yy: 'ọdún %d', + }, + dayOfMonthOrdinalParse: /ọjọ́\s\d{1,2}/, + ordinal: 'ọjọ́ %d', + week: { + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('zh-cn', { + months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split( + '_' + ), + monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split( + '_' + ), + weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), + weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'), + weekdaysMin: '日_一_二_三_四_五_六'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY/MM/DD', + LL: 'YYYY年M月D日', + LLL: 'YYYY年M月D日Ah点mm分', + LLLL: 'YYYY年M月D日ddddAh点mm分', + l: 'YYYY/M/D', + ll: 'YYYY年M月D日', + lll: 'YYYY年M月D日 HH:mm', + llll: 'YYYY年M月D日dddd HH:mm', + }, + meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') { + return hour; + } else if (meridiem === '下午' || meridiem === '晚上') { + return hour + 12; + } else { + // '中午' + return hour >= 11 ? hour : hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + var hm = hour * 100 + minute; + if (hm < 600) { + return '凌晨'; + } else if (hm < 900) { + return '早上'; + } else if (hm < 1130) { + return '上午'; + } else if (hm < 1230) { + return '中午'; + } else if (hm < 1800) { + return '下午'; + } else { + return '晚上'; + } + }, + calendar: { + sameDay: '[今天]LT', + nextDay: '[明天]LT', + nextWeek: function (now) { + if (now.week() !== this.week()) { + return '[下]dddLT'; + } else { + return '[本]dddLT'; + } + }, + lastDay: '[昨天]LT', + lastWeek: function (now) { + if (this.week() !== now.week()) { + return '[上]dddLT'; + } else { + return '[本]dddLT'; + } + }, + sameElse: 'L', + }, + dayOfMonthOrdinalParse: /\d{1,2}(日|月|周)/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + '日'; + case 'M': + return number + '月'; + case 'w': + case 'W': + return number + '周'; + default: + return number; + } + }, + relativeTime: { + future: '%s后', + past: '%s前', + s: '几秒', + ss: '%d 秒', + m: '1 分钟', + mm: '%d 分钟', + h: '1 小时', + hh: '%d 小时', + d: '1 天', + dd: '%d 天', + w: '1 周', + ww: '%d 周', + M: '1 个月', + MM: '%d 个月', + y: '1 年', + yy: '%d 年', + }, + week: { + // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 + dow: 1, // Monday is the first day of the week. + doy: 4, // The week that contains Jan 4th is the first week of the year. + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('zh-hk', { + months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split( + '_' + ), + monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split( + '_' + ), + weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), + weekdaysShort: '週日_週一_週二_週三_週四_週五_週六'.split('_'), + weekdaysMin: '日_一_二_三_四_五_六'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY/MM/DD', + LL: 'YYYY年M月D日', + LLL: 'YYYY年M月D日 HH:mm', + LLLL: 'YYYY年M月D日dddd HH:mm', + l: 'YYYY/M/D', + ll: 'YYYY年M月D日', + lll: 'YYYY年M月D日 HH:mm', + llll: 'YYYY年M月D日dddd HH:mm', + }, + meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') { + return hour; + } else if (meridiem === '中午') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === '下午' || meridiem === '晚上') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + var hm = hour * 100 + minute; + if (hm < 600) { + return '凌晨'; + } else if (hm < 900) { + return '早上'; + } else if (hm < 1200) { + return '上午'; + } else if (hm === 1200) { + return '中午'; + } else if (hm < 1800) { + return '下午'; + } else { + return '晚上'; + } + }, + calendar: { + sameDay: '[今天]LT', + nextDay: '[明天]LT', + nextWeek: '[下]ddddLT', + lastDay: '[昨天]LT', + lastWeek: '[上]ddddLT', + sameElse: 'L', + }, + dayOfMonthOrdinalParse: /\d{1,2}(日|月|週)/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + '日'; + case 'M': + return number + '月'; + case 'w': + case 'W': + return number + '週'; + default: + return number; + } + }, + relativeTime: { + future: '%s後', + past: '%s前', + s: '幾秒', + ss: '%d 秒', + m: '1 分鐘', + mm: '%d 分鐘', + h: '1 小時', + hh: '%d 小時', + d: '1 天', + dd: '%d 天', + M: '1 個月', + MM: '%d 個月', + y: '1 年', + yy: '%d 年', + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('zh-mo', { + months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split( + '_' + ), + monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split( + '_' + ), + weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), + weekdaysShort: '週日_週一_週二_週三_週四_週五_週六'.split('_'), + weekdaysMin: '日_一_二_三_四_五_六'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'DD/MM/YYYY', + LL: 'YYYY年M月D日', + LLL: 'YYYY年M月D日 HH:mm', + LLLL: 'YYYY年M月D日dddd HH:mm', + l: 'D/M/YYYY', + ll: 'YYYY年M月D日', + lll: 'YYYY年M月D日 HH:mm', + llll: 'YYYY年M月D日dddd HH:mm', + }, + meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') { + return hour; + } else if (meridiem === '中午') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === '下午' || meridiem === '晚上') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + var hm = hour * 100 + minute; + if (hm < 600) { + return '凌晨'; + } else if (hm < 900) { + return '早上'; + } else if (hm < 1130) { + return '上午'; + } else if (hm < 1230) { + return '中午'; + } else if (hm < 1800) { + return '下午'; + } else { + return '晚上'; + } + }, + calendar: { + sameDay: '[今天] LT', + nextDay: '[明天] LT', + nextWeek: '[下]dddd LT', + lastDay: '[昨天] LT', + lastWeek: '[上]dddd LT', + sameElse: 'L', + }, + dayOfMonthOrdinalParse: /\d{1,2}(日|月|週)/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + '日'; + case 'M': + return number + '月'; + case 'w': + case 'W': + return number + '週'; + default: + return number; + } + }, + relativeTime: { + future: '%s內', + past: '%s前', + s: '幾秒', + ss: '%d 秒', + m: '1 分鐘', + mm: '%d 分鐘', + h: '1 小時', + hh: '%d 小時', + d: '1 天', + dd: '%d 天', + M: '1 個月', + MM: '%d 個月', + y: '1 年', + yy: '%d 年', + }, + }); + + //! moment.js locale configuration + + hooks.defineLocale('zh-tw', { + months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split( + '_' + ), + monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split( + '_' + ), + weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), + weekdaysShort: '週日_週一_週二_週三_週四_週五_週六'.split('_'), + weekdaysMin: '日_一_二_三_四_五_六'.split('_'), + longDateFormat: { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L: 'YYYY/MM/DD', + LL: 'YYYY年M月D日', + LLL: 'YYYY年M月D日 HH:mm', + LLLL: 'YYYY年M月D日dddd HH:mm', + l: 'YYYY/M/D', + ll: 'YYYY年M月D日', + lll: 'YYYY年M月D日 HH:mm', + llll: 'YYYY年M月D日dddd HH:mm', + }, + meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, + meridiemHour: function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === '凌晨' || meridiem === '早上' || meridiem === '上午') { + return hour; + } else if (meridiem === '中午') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === '下午' || meridiem === '晚上') { + return hour + 12; + } + }, + meridiem: function (hour, minute, isLower) { + var hm = hour * 100 + minute; + if (hm < 600) { + return '凌晨'; + } else if (hm < 900) { + return '早上'; + } else if (hm < 1130) { + return '上午'; + } else if (hm < 1230) { + return '中午'; + } else if (hm < 1800) { + return '下午'; + } else { + return '晚上'; + } + }, + calendar: { + sameDay: '[今天] LT', + nextDay: '[明天] LT', + nextWeek: '[下]dddd LT', + lastDay: '[昨天] LT', + lastWeek: '[上]dddd LT', + sameElse: 'L', + }, + dayOfMonthOrdinalParse: /\d{1,2}(日|月|週)/, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'DDD': + return number + '日'; + case 'M': + return number + '月'; + case 'w': + case 'W': + return number + '週'; + default: + return number; + } + }, + relativeTime: { + future: '%s後', + past: '%s前', + s: '幾秒', + ss: '%d 秒', + m: '1 分鐘', + mm: '%d 分鐘', + h: '1 小時', + hh: '%d 小時', + d: '1 天', + dd: '%d 天', + M: '1 個月', + MM: '%d 個月', + y: '1 年', + yy: '%d 年', + }, + }); + + hooks.locale('en'); + + return hooks; + +}))); diff --git a/public/scripts/ol-min.js b/public/scripts/ol-min.js index 17d6974d..cca34863 100644 --- a/public/scripts/ol-min.js +++ b/public/scripts/ol-min.js @@ -1 +1,1039 @@ -!function(t,e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define([],e):t.ol=e()}(this,function(){var F={},k=this;function t(t,e){var o,i=F;(t=t.split("."))[0]in(i=i||k)||!i.execScript||i.execScript("var "+t[0]);for(;t.length&&(o=t.shift());)t.length||void 0===e?i=i[o]&&i[o]!==Object.prototype[o]?i[o]:i[o]={}:i[o]=e}function G(t,e){return e>>0,r=0;r=e.ca&&t.da<=e.ia&&t.ia>=e.da}function Q(t,e,o){return Math.min(Math.max(t,e),o)}e(q,Error);var tt="cosh"in Math?Math.cosh:function(t){return((t=Math.exp(t))+1/t)/2};function et(t,e,o,i,r,n){var s,a=r-o,p=n-i;return(a||p)&&(1<(s=((t-o)*a+(e-i)*p)/(a*a+p*p))?(o=r,i=n):0t[2]&&(t[2]=e[2]),e[1]t[3]&&(t[3]=e[3]),t}function Pt(t,e){e[0]t[2]&&(t[2]=e[0]),e[1]t[3]&&(t[3]=e[1])}function At(t,e,o,i,r){for(;oe[0]?t:e)[0],o[1]=(t[1]>e[1]?t:e)[1],o[2]=(t[2]=e[0]&&t[1]<=e[3]&&t[3]>=e[1]}function Ut(t){return t[2]=t.minZoom;){if(o.call(null,e,Ie(t,r,e,i)))return!0;--e}return!1}function Le(t,e,o,i){return e[0]T.$)&&($(E,new J(rt(M.ca,j),rt(M.$,j),M.da,M.ia))||M.$-M.ca+1>j&&$(E,T))){m=!0;break t}}m=!1}else m=!0}else m=!1;m?(b in l&&delete l[b],(m=v.b)in u||(u[m]=!0,h[b]=v)):l[b]=v}}}for(r in f=(a=[h,l])[0],a=a[1],this.l)r in f?(this.j[r]||(this.l[r].style.display="",this.j[r]=!0),delete f[r]):r in a?(this.j[r]&&(this.l[r].style.display="none",delete this.j[r]),delete a[r]):(Eo(this.l[r]),delete this.l[r],delete this.j[r]);for(r in f)g=document.createElement("LI"),g.innerHTML=f[r].b,this.I.appendChild(g),this.l[r]=g,this.j[r]=!0;for(r in a)g=document.createElement("LI"),g.innerHTML=a[r].b,g.style.display="none",this.I.appendChild(g),this.l[r]=g;for(s in r=!Zt(this.j)||!Zt(t.logos),this.B!=r&&(this.element.style.display=r?"":"none",this.B=r),r&&Zt(this.j)?this.element.classList.add("ol-logo-only"):this.element.classList.remove("ol-logo-only"),t=t.logos,r=this.T)s in t||(Eo(r[s]),delete r[s]);for(n in t)(a=t[n])instanceof HTMLElement&&(this.u.appendChild(a),r[n]=a),n in r||((s=new Image).src=n,""===a?f=s:((f=document.createElement("a")).href=a,f.appendChild(s)),this.u.appendChild(f),r[n]=f);this.u.style.display=Zt(t)?"none":""}else this.B&&(this.element.style.display="none",this.B=!1)}function Lo(t){t.element.classList.toggle("ol-collapsed"),t.c?Ao(t.D,t.C):Ao(t.C,t.D),t.c=!t.c}function Ro(t){return Math.pow(t,3)}function Io(t){return 1-Ro(1-t)}function No(t){return 3*t*t-2*t*t*t}function Fo(t){return t}function ko(t){var e=void 0!==(t=t||{}).className?t.className:"ol-rotate",o=void 0!==t.label?t.label:"⇧",i=(this.c=null,"string"==typeof o?(this.c=document.createElement("span"),this.c.className="ol-compass",this.c.textContent=o):(this.c=o,this.c.classList.add("ol-compass")),t.tipLabel||"Reset rotation");(o=document.createElement("button")).className=e+"-reset",o.setAttribute("type","button"),o.title=i,o.appendChild(this.c),d(o,"click",ko.prototype.D,this),(i=document.createElement("div")).className=e+" ol-unselectable ol-control",i.appendChild(o),e=t.render||Do,this.o=t.resetNorth||void 0,To.call(this,{element:i,render:e,target:t.target}),this.l=void 0!==t.duration?t.duration:250,this.j=void 0===t.autoHide||t.autoHide,this.u=void 0,this.j&&this.element.classList.add("ol-hidden")}function Do(t){var e,o;(t=t.frameState)&&((t=t.viewState.rotation)!=this.u&&(e="rotate("+t+"rad)",this.j&&((o=this.element.classList.contains("ol-hidden"))||t?o&&t&&this.element.classList.remove("ol-hidden"):this.element.classList.add("ol-hidden")),this.c.style.msTransform=e,this.c.style.webkitTransform=e,this.c.style.transform=e),this.u=t)}function Oo(t){var e=void 0!==(t=t||{}).className?t.className:"ol-zoom",o=void 0!==t.delta?t.delta:1,i=void 0!==t.zoomInLabel?t.zoomInLabel:"+",r=void 0!==t.zoomOutLabel?t.zoomOutLabel:"−",n=void 0!==t.zoomInTipLabel?t.zoomInTipLabel:"Zoom in",s=void 0!==t.zoomOutTipLabel?t.zoomOutTipLabel:"Zoom out",a=document.createElement("button");a.className=e+"-in",a.setAttribute("type","button"),a.title=n,a.appendChild("string"==typeof i?document.createTextNode(i):i),d(a,"click",Oo.prototype.j.bind(this,o)),(i=document.createElement("button")).className=e+"-out",i.setAttribute("type","button"),i.title=s,i.appendChild("string"==typeof r?document.createTextNode(r):r),d(i,"click",Oo.prototype.j.bind(this,-o)),(o=document.createElement("div")).className=e+" ol-unselectable ol-control",o.appendChild(a),o.appendChild(i),To.call(this,{element:o,target:t.target}),this.c=void 0!==t.duration?t.duration:250}function Uo(t){t=t||{};var e=new ho;return void 0!==t.zoom&&!t.zoom||e.push(new Oo(t.zoomOptions)),void 0!==t.rotate&&!t.rotate||e.push(new ko(t.rotateOptions)),void 0!==t.attribution&&!t.attribution||e.push(new jo(t.attributionOptions)),e}function Go(t){this.c=void 0!==(t=t||{}).className?t.className:"ol-full-screen";var e=void 0!==t.label?t.label:"⤢",o=(this.o="string"==typeof e?document.createTextNode(e):e,e=void 0!==t.labelActive?t.labelActive:"×",this.l="string"==typeof e?document.createTextNode(e):e,t.tipLabel||"Toggle full-screen");(e=document.createElement("button")).className=this.c+"-"+Xo(),e.setAttribute("type","button"),e.title=o,e.appendChild(this.o),d(e,"click",this.C,this),(o=document.createElement("div")).className=this.c+" ol-unselectable ol-control "+(Bo()?"":"ol-unsupported"),o.appendChild(e),To.call(this,{element:o,target:t.target}),this.D=void 0!==t.keys&&t.keys,this.j=t.source}function Bo(){var t=document.body;return t.webkitRequestFullscreen||t.mozRequestFullScreen&&document.mozFullScreenEnabled||t.msRequestFullscreen&&document.msFullscreenEnabled||t.requestFullscreen&&document.fullscreenEnabled}function Xo(){return!!(document.webkitIsFullScreen||document.mozFullScreen||document.msFullscreenElement||document.fullscreenElement)}function Vo(t){t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.mozRequestFullScreen?t.mozRequestFullScreen():t.webkitRequestFullscreen&&t.webkitRequestFullscreen()}e(To,ro),To.prototype.ka=function(){Eo(this.element),ro.prototype.ka.call(this)},To.prototype.g=function(){return this.a},To.prototype.setMap=function(t){this.a&&Eo(this.element);for(var e=0,o=this.v.length;e=e.length){for(var r=[],n=0;nt.D||Math.abs(e.clientY-t.c.clientY)>t.D}function Zi(t,e){this.l=t,this.c=e,this.b=[],this.i=[],this.a={}}function Ki(t){var e=t.b,o=t.i,i=e[0];return 1==e.length?(e.length=0,o.length=0):(e[0]=e.pop(),o[0]=o.pop(),zi(t,0)),e=t.c(i),delete t.a[e],i}function zi(t,e){for(var o=t.b,i=t.i,r=o.length,n=o[e],s=i[e],a=e;e>1;){var p=2*e+1,h=2*e+2,p=h>1;if(!(t[s]>n))break;i[o]=i[s],t[o]=t[s],o=s}i[o]=r,t[o]=n}function Hi(t){for(var e=t.l,o=t.b,i=t.i,r=0,n=o.length,s=0;s>1)-1;0<=e;e--)zi(t,e)}function qi(e,t){Zi.call(this,function(t){return e.apply(null,t)},function(t){return t[0].bb()}),this.v=t,this.j=0,this.g={}}function Ji(t,e,o){for(var i,r,n=0;t.j=l[0]&&r[2]<=l[2]||r[1]>=l[1]&&r[3]<=l[3])||Gr(t,e,o,i,function(t,e){var o,i,r,n,s,a=!1,p=dt(l,t),h=dt(l,e);return 1===p||1===h?a=!0:(o=l[0],i=l[1],r=l[2],n=l[3],s=e[0],t=((e=e[1])-t[1])/(s-t[0]),(a=(a=(a=2&h&&!(2&p)?o<=(a=s-(e-n)/t)&&a<=r:a)||!(4&h)||4&p?a:i<=(a=e-(s-r)*t)&&a<=n)||!(8&h)||8&p?a:o<=(a=s-(e-i)/t)&&a<=r)||!(16&h)||16&p||(a=i<=(a=e-(s-o)*t)&&a<=n)),a}))}function Xr(t,e,o,i,r){var n=o[0];if(!(Br(t,e,n,i,r)||Dr(t,e,n,i,r[0],r[1])||Dr(t,e,n,i,r[0],r[3])||Dr(t,e,n,i,r[2],r[1])||Dr(t,e,n,i,r[2],r[3])))return!1;if(1!==o.length)for(e=1,n=o.length;ee;)r-=3;if(!((e=t.b[2+o]-t.b[r+2])<1e3/60))return i=t.b[o]-t.b[r],o=t.b[1+o]-t.b[r+1],t.i=Math.atan2(o,i),t.a=Math.sqrt(i*i+o*o)/e,t.a>t.c}}}(this.a)&&(e=((e=this.a).c-e.a)/e.f,o=this.a.i,i=t.wa(),i=r.Ja(i),r=r.Wa([i[0]-e*Math.cos(o),i[1]-e*Math.sin(o)]),t.animate({center:t.Ec(r),duration:500,easing:Io})),nn(t,1,-1),!1)}function Cn(t){var e;return!!(0=this.u}function Gn(t){var e,o;xn(t)&&(e=this.a,o=t.pixel,e.c=this.g,e.i=o,Dn(e),kn(e),this.b(new Kn(Wn,t.coordinate,t)))}function Bn(t){return!xn(t)||(this.a.setMap(null),this.l(t,this.g,t.pixel)&&(this.j(t),this.b(new Kn(Zn,t.coordinate,t))),!1)}function Xn(t){var e,o;return!!(xn(t)&&gn(t)&&this.C(t))&&(this.g=t.pixel,this.a.setMap(t.map),e=this.a,o=this.g,e.c=this.g,e.i=o,Dn(e),kn(e),this.b(new Kn(Vn,t.coordinate,t)),!0)}e(Xi,eo),(r=Xi.prototype).Jh=function(t){Vi(this,t);var e,o=new mi("pointerup",this.i,t);this.b(o),this.o||t.button||(e=(o=this).c,t=new mi("click",o.i,e),o.b(t),o.j?(clearTimeout(o.j),o.j=0,t=new mi("dblclick",o.i,e),o.b(t)):o.j=setTimeout(function(){this.j=0;var t=new mi("singleclick",this.i,e);this.b(t)}.bind(o),250)),this.S||(this.f.forEach(qe),this.f.length=0,this.o=!1,this.c=null,$e(this.a),this.a=null)},r.Ol=function(t){Vi(this,t);var e=new mi("pointerdown",this.i,t);this.b(e),this.c=t,this.f.length||(this.a=new Ii(document),this.f.push(d(this.a,"pointermove",this.Hm,this),d(this.a,"pointerup",this.Jh,this),d(this.g,"pointercancel",this.Jh,this)))},r.Hm=function(t){var e;Wi(this,t)&&(this.o=!0,e=new mi("pointerdrag",this.i,t,this.o),this.b(e)),t.preventDefault()},r.Lp=function(t){this.b(new mi(t.type,this.i,t,!(!this.c||!Wi(this,t))))},r.ka=function(){this.v&&(qe(this.v),this.v=null),this.l&&(qe(this.l),this.l=null),this.f.forEach(qe),this.f.length=0,this.a&&($e(this.a),this.a=null),this.g&&($e(this.g),this.g=null),eo.prototype.ka.call(this)},Zi.prototype.clear=function(){this.b.length=0,this.i.length=0,Vt(this.a)},Zi.prototype.f=function(t){O(!(this.c(t)in this.a),31);var e=this.l(t);return 1/0!=e&&(this.b.push(t),this.i.push(e),this.a[this.c(t)]=!0,Yi(this,0,this.b.length-1),!0)},e(qi,Zi),qi.prototype.f=function(t){var e=Zi.prototype.f.call(this,t);return e&&d(t[0],"change",this.o,this),e},qi.prototype.o=function(t){var e=(t=t.target).getState();2!==e&&3!==e&&4!==e&&5!==e||(He(t,"change",this.o,this),(t=t.bb())in this.g&&(delete this.g[t],--this.j),this.v())},e(yr,ro),(r=yr.prototype).Ab=function(t,e){return this.Kb(t[0],t[1],e=e||[NaN,NaN],1/0),e},r.sb=function(t){return this.Mc(t[0],t[1])},r.Mc=fr,r.G=function(t){this.v!=this.i&&(this.l=this.se(this.l),this.v=this.i);var e=this.l;return t?(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3]):t=e,t},r.Rb=function(t){return this.Vd(t*t)},r.tb=function(t,e){return this.Dc(me(t,e)),this},e(b,yr),(r=b.prototype).Mc=fr,r.se=function(t){return xt(this.A,0,this.A.length,this.a,t)},r.ac=function(){return this.A.slice(0,this.a)},r.ga=function(){return this.A},r.bc=function(){return this.A.slice(this.A.length-this.a)},r.cc=function(){return this.ja},r.Vd=function(t){if(this.o!=this.i&&(Vt(this.f),this.g=0,this.o=this.i),!(t<0||this.g&&t<=this.g)){var e=t.toString();if(this.f.hasOwnProperty(e))return this.f[e];var o=this.hd(t);if(o.ga().length=this.f&&t<=this.a){var e=this.l||0;if(this.j){if(e+=i=B(this.j,t,1),i==this.j.length-1)return e;var o=this.j[i],i=o/this.j[i+1]}else o=this.a,i=this.C;e+=Math.log(o/t)/Math.log(i)}return e},r.Qf=function(t,e){var o=(o=(e=e||{}).size)||en(this);t instanceof b?"Circle"===t.U()?(f=Hr(t=t.G())).rotate(this.Qa(),Lt(t)):f=t:(O(Array.isArray(t),24),O(!Ut(t),25),f=Hr(t));for(var i=e.padding||[0,0,0,0],r=void 0===e.constrainResolution||e.constrainResolution,n=void 0!==e.nearest&&e.nearest,s=void 0!==e.minResolution?e.minResolution:void 0!==e.maxZoom?this.constrainResolution(this.a,e.maxZoom-this.l,0):0,a=f.ga(),p=this.Qa(),p=(t=Math.cos(-p),Math.sin(-p)),h=1/0,l=1/0,u=-1/0,c=-1/0,f=f.qa(),y=0,g=a.length;ythis.C&&(this.a=!0),this.j=i,(i=(t=t.map).Z()).g.rotation!==_i&&(r=t.a.getBoundingClientRect(),(e=Pn(this.o))[0]-=r.left,e[1]-=r.top,this.g=t.Wa(e),this.a)&&(r=i.Qa(),t.render(),hn(i,r+o,this.g))}function is(t){var e,o,i;return!(this.o.length<2&&(nn(t=t.map.Z(),1,-1),this.a&&(i=t.Qa(),e=this.g,o=this.u,i=t.constrainRotation(i,0),hn(t,i,e,o)),1))}function rs(t){return 2<=this.o.length&&(t=t.map,this.g=null,this.j=void 0,this.a=!1,this.l=0,this.D||nn(t.Z(),1,1),!0)}function ns(t){Mn.call(this,{handleDownEvent:ps,handleDragEvent:ss,handleUpEvent:as}),this.l=(t=t||{}).constrainResolution||!1,this.g=null,this.u=void 0!==t.duration?t.duration:400,this.a=void 0,this.j=1}function ss(t){var e=1,o=this.o[0],i=this.o[1],r=o.clientX-i.clientX,o=o.clientY-i.clientY,r=Math.sqrt(r*r+o*o);void 0!==this.a&&(e=this.a/r),this.a=r;var i=(r=(t=t.map).Z()).Pa(),n=r.a,s=r.f;n<(o=i*e)?(e=n/i,o=n):ot.a)&&(e=this.g,o=this.u,i=t.constrainResolution(i,0,this.j-1),un(t,i,e,o)),1))}function ps(t){return 2<=this.o.length&&(t=t.map,this.g=null,this.a=void 0,this.j=1,this.D||nn(t.Z(),1,1),!0)}function hs(t){t=t||{};var e=new ho,o=new sn(-.005,.05,100);return void 0!==t.altShiftDragRotate&&!t.altShiftDragRotate||e.push(new Ln),void 0!==t.doubleClickZoom&&!t.doubleClickZoom||e.push(new cn({delta:t.zoomDelta,duration:t.zoomDuration})),void 0!==t.dragPan&&!t.dragPan||e.push(new En({kinetic:o})),void 0!==t.pinchRotate&&!t.pinchRotate||e.push(new es),void 0!==t.pinchZoom&&!t.pinchZoom||e.push(new ns({constrainResolution:t.constrainResolution,duration:t.zoomDuration})),void 0!==t.keyboard&&!t.keyboard||(e.push(new Yn),e.push(new qn({delta:t.zoomDelta,duration:t.zoomDuration}))),void 0!==t.mouseWheelZoom&&!t.mouseWheelZoom||e.push(new _n({constrainResolution:t.constrainResolution,duration:t.zoomDuration})),void 0!==t.shiftDragZoom&&!t.shiftDragZoom||e.push(new zn({duration:t.zoomDuration})),e}function ls(t){ro.call(this);var e=Xt({},t);e.opacity=void 0!==t.opacity?t.opacity:1,e.visible=void 0===t.visible||t.visible,e.zIndex=void 0!==t.zIndex?t.zIndex:0,e.maxResolution=void 0!==t.maxResolution?t.maxResolution:1/0,e.minResolution=void 0!==t.minResolution?t.minResolution:0,this.H(e),this.a={layer:this,Je:!0}}function us(t){return t.a.opacity=Q(t.hc(),0,1),t.a.yj=t.$f(),t.a.visible=t.Mb(),t.a.extent=t.G(),t.a.zIndex=t.Ba(),t.a.maxResolution=t.fc(),t.a.minResolution=Math.max(t.gc(),0),t.a}function cs(t){var e=t||{};delete(t=Xt({},e)).layers,e=e.layers,ls.call(this,t),this.f=[],this.c={},d(this,so(fs),this.Hl,this),e?Array.isArray(e)?e=new ho(e.slice(),{unique:!0}):O(e instanceof ho,43):e=new ho(void 0,{unique:!0}),this.xi(e)}e(es,Mn),es.prototype.Xc=fr,e(ns,Mn),ns.prototype.Xc=fr,e(ls,ro),(r=ls.prototype).G=function(){return this.get("extent")},r.fc=function(){return this.get("maxResolution")},r.gc=function(){return this.get("minResolution")},r.hc=function(){return this.get("opacity")},r.Mb=function(){return this.get("visible")},r.Ba=function(){return this.get("zIndex")},r.vc=function(t){this.set("extent",t)},r.Ac=function(t){this.set("maxResolution",t)},r.Bc=function(t){this.set("minResolution",t)},r.wc=function(t){this.set("opacity",t)},r.xc=function(t){this.set("visible",t)},r.Vb=function(t){this.set("zIndex",t)},e(cs,ls),(r=cs.prototype).Fd=function(){},r.Fe=function(){this.Mb()&&this.s()},r.Hl=function(){this.f.forEach(qe),this.f.length=0;var t=this.qd();for(e in this.f.push(d(t,"add",this.Gl,this),d(t,"remove",this.Il,this)),this.c)this.c[e].forEach(qe);Vt(this.c);for(var e=0,o=(t=t.a).length;e=t.minResolution&&eu[2])&&(c=[y+h*Math.ceil((u[0]-y)/h),t[1]]),h=(u=r.layerStatesArray).length-1;0<=h;--h){var f=u[h],y=f.layer;if(gs(f,l)&&o.call(i,y)&&(f=Ns(this,y),p=y.ha()?f.Ea(y.ha().u?c:t,r,e,a,s):p))return p}},r.Ei=function(t,e,o,i,r){return void 0!==this.Ea(t,e,o,cr,this,i,r)},r.Fl=function(){this.o.render()},r.Jg=Y,r.Rp=function(t,e){for(var o in this.c)e&&o in e.layerStates||(t=o,o=this.c[t],delete this.c[t],qe(this.v[t]),delete this.v[t],$e(o))},e(Ds,Qe);var Os=[0,0,0,1],Us=[],Gs=[0,0,0,1];function Bs(t,e,o,i){e&&(t.translate(o,i),t.rotate(e),t.translate(-o,-i))}function Xs(){}function Vs(t,e,o,i,r){this.i=t,this.u=e,this.c=o,this.S=i,this.Yb=r,this.M=this.b=this.a=this.Ua=this.R=this.I=null,this.na=this.T=this.l=this.B=this.C=this.D=0,this.fa=!1,this.f=this.fb=0,this.pa=!1,this.oa=0,this.Ia="",this.va=this.Jb=0,this.Sa=!1,this.j=this.$a=0,this.ra=this.o=this.g=null,this.v=[],this.xb=ms()}function Ws(t,e,o){if(t.M){e=gr(e,0,o,2,t.S,t.v),o=t.i;for(var i=t.xb,r=o.globalAlpha,n=(1!=t.l&&(o.globalAlpha=r*t.l),t.fb),s=(t.fa&&(n+=t.Yb),0),a=e.length;s=a;){var p=this.i[s];o[U(this.f[s]).toString()]&&(i!==n&&la(t,e,i,n),n=p),s--,i=p}i!==n&&la(t,e,i,n),i=n=a}},r.ve=function(t,e,o,i,r){for(var n,s=this.i.length-2,a=this.i[s+1],p=this.u.length-1;0<=p;--p){var h=this.j[p];for(t.uniform4fv(this.v.B,h[0]),ma(this,t,h[1],h[2]),n=this.u[p];0<=s&&this.i[s]>=n;){var h=this.i[s],l=this.f[s];if(void 0===o[U(l).toString()]&&l.V()&&(void 0===r||Ot(r,l.V().G()))&&(t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT),la(t,e,h,a),a=i(l)))return a;s--,a=h}}},r.Ma=function(t,e){var o;e=e?(o=e.i,this.c.lineDash=o||ca,o=e.g,this.c.lineDashOffset=o||0,o=!((o=e.a)instanceof CanvasGradient||o instanceof CanvasPattern)&&vo(o).map(function(t,e){return 3!=e?t/255:t})||fa,void 0!==(e=e.c)?e:1):(o=[0,0,0,0],0),t=!((t=t?t.b:[0,0,0,0])instanceof CanvasGradient||t instanceof CanvasPattern)&&vo(t).map(function(t,e){return 3!=e?t/255:t})||ua,this.c.strokeColor&&Z(this.c.strokeColor,o)&&this.c.fillColor&&Z(this.c.fillColor,t)&&this.c.lineWidth===e||(this.c.s=!0,this.c.fillColor=t,this.c.strokeColor=o,this.c.lineWidth=e,this.j.push([t,o,e]))},e(wa,ta);var xa=new wa;function Sa(){this.b="varying vec2 a;varying float b;attribute vec2 c;attribute vec2 d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;void main(void){mat4 offsetMatrix=i;if(g==1.0){offsetMatrix=i*j;}vec4 offsets=offsetMatrix*vec4(e,0.0,0.0);gl_Position=h*vec4(c,0.0,1.0)+offsets;a=d;b=f;}"}e(Sa,ea);var Ma=new Sa;function Pa(t,e){this.c=t.getUniformLocation(e,"j"),this.f=t.getUniformLocation(e,"i"),this.a=t.getUniformLocation(e,"k"),this.i=t.getUniformLocation(e,"h"),this.v=t.getAttribLocation(e,"e"),this.u=t.getAttribLocation(e,"f"),this.b=t.getAttribLocation(e,"c"),this.D=t.getAttribLocation(e,"g"),this.C=t.getAttribLocation(e,"d")}function Aa(t,e){this.j=t,this.b=e,this.a={},this.c={},this.i={},this.l=this.v=this.f=this.o=null,(this.g=D(di,"OES_element_index_uint"))&&e.getExtension("OES_element_index_uint"),d(this.j,"webglcontextlost",this.Xo,this),d(this.j,"webglcontextrestored",this.Yo,this)}function Ea(t,e,o){var i,r,n=t.b,s=o.b,a=String(U(o));a in t.a?n.bindBuffer(e,t.a[a].buffer):(i=n.createBuffer(),n.bindBuffer(e,i),34962==e?r=new Float32Array(s):34963==e&&(r=new(t.g?Uint32Array:Uint16Array)(s)),n.bufferData(e,r,o.a),t.a[a]={lc:o,buffer:i})}function Ta(t,e){var o=t.b,i=(e=String(U(e)),t.a[e]);o.isContextLost()||o.deleteBuffer(i.buffer),delete t.a[e]}function ja(t){var e,o,i,r;return t.f||(o=(e=t.b).createFramebuffer(),e.bindFramebuffer(e.FRAMEBUFFER,o),i=Ia(e,1,1),r=e.createRenderbuffer(),e.bindRenderbuffer(e.RENDERBUFFER,r),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_COMPONENT16,1,1),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,i,0),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.RENDERBUFFER,r),e.bindTexture(e.TEXTURE_2D,null),e.bindRenderbuffer(e.RENDERBUFFER,null),e.bindFramebuffer(e.FRAMEBUFFER,null),t.f=o,t.v=i,t.l=r),t.f}function Ca(t,e){var o,i,r=String(U(e));return r in t.c?t.c[r]:(i=(o=t.b).createShader(e.U()),o.shaderSource(i,e.b),o.compileShader(i),t.c[r]=i)}function La(t,e,o){var i,r,n=U(e)+"/"+U(o);return n in t.i?t.i[n]:(r=(i=t.b).createProgram(),i.attachShader(r,Ca(t,e)),i.attachShader(r,Ca(t,o)),i.linkProgram(r),t.i[n]=r)}function Ra(t,e,o){var i=t.createTexture();return t.bindTexture(t.TEXTURE_2D,i),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),void 0!==e&&t.texParameteri(3553,10242,e),void 0!==o&&t.texParameteri(3553,10243,o),i}function Ia(t,e,o){var i=Ra(t,void 0,void 0);return t.texImage2D(t.TEXTURE_2D,0,t.RGBA,e,o,0,t.RGBA,t.UNSIGNED_BYTE,null),i}function Na(t,e){var o=Ra(t,33071,33071);return t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,e),o}function Fa(t,e){ha.call(this,0,e),this.C=this.D=void 0,this.S=[],this.v=[],this.oa=void 0,this.j=[],this.c=[],this.I=this.ra=void 0,this.B=null,this.fb=this.fa=this.na=this.T=this.Ua=this.R=void 0,this.va=[],this.u=[],this.pa=void 0}function ka(t,e,o,i){for(var r=t.D,n=t.C,s=t.oa,a=t.ra,p=t.I,h=t.R,l=t.Ua,u=t.T,c=t.na?1:0,f=-t.fa,y=t.fb,g=t.pa,d=Math.cos(f),f=Math.sin(f),v=t.b.length,b=t.a.length,m=0;m=a;){var h=this.i[n],l=this.f[n];if(void 0===o[U(l).toString()]&&l.V()&&(void 0===r||Ot(r,l.V().G()))&&(t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT),la(t,e,h,p),p=i(l)))return p;p=h,n--}}},r.Ub=function(t){var e=t.Hc(),o=t.Y(1),i=t.ye(),r=t.qg(1),n=t.f,s=t.Oc(),a=t.l,p=t.g,h=t.ic();t=t.a,this.j.length?U(this.j[this.j.length-1])!=U(o)&&(this.S.push(this.b.length),this.j.push(o)):this.j.push(o),this.c.length?U(this.c[this.c.length-1])!=U(r)&&(this.v.push(this.b.length),this.c.push(r)):this.c.push(r),this.D=e[0],this.C=e[1],this.oa=h[1],this.ra=i[1],this.I=i[0],this.R=n,this.Ua=s[0],this.T=s[1],this.fa=p,this.na=a,this.fb=t,this.pa=h[0]},e(Ua,ta);var Ga=new Ua;function Ba(){this.b="varying float a;varying vec2 b;varying float c;attribute vec2 d;attribute vec2 e;attribute vec2 f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;bool nearlyEquals(in float value,in float ref){float epsilon=0.000000000001;return value>=ref-epsilon&&value<=ref+epsilon;}void alongNormal(out vec2 offset,in vec2 nextP,in float turnDir,in float direction){vec2 dirVect=nextP-e;vec2 normal=normalize(vec2(-turnDir*dirVect.y,turnDir*dirVect.x));offset=k/2.0*normal*direction;}void miterUp(out vec2 offset,out float round,in bool isRound,in float direction){float halfWidth=k/2.0;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=f-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;round=0.0;if(isRound){round=1.0;}else if(miterLength>l+k){offset=halfWidth*tmpNormal*direction;}} bool miterDown(out vec2 offset,in vec4 projPos,in mat4 offsetMatrix,in float direction){bool degenerate=false;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=d-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));vec2 longOffset,shortOffset,longVertex;vec4 shortProjVertex;float halfWidth=k/2.0;if(length(f-e)>length(d-e)){longOffset=tmpNormal*direction*halfWidth;shortOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=f;shortProjVertex=h*vec4(d,0.0,1.0);}else{shortOffset=tmpNormal*direction*halfWidth;longOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=d;shortProjVertex=h*vec4(f,0.0,1.0);}vec4 p1=h*vec4(longVertex,0.0,1.0)+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p2=projPos+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p3=shortProjVertex+offsetMatrix*vec4(-shortOffset,0.0,0.0);vec4 p4=shortProjVertex+offsetMatrix*vec4(shortOffset,0.0,0.0);float denom=(p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y);float firstU=((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/denom;float secondU=((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/denom;float epsilon=0.000000000001;if(firstU>epsilon&&firstU<1.0-epsilon&&secondU>epsilon&&secondU<1.0-epsilon){shortProjVertex.x=p1.x+firstU*(p2.x-p1.x);shortProjVertex.y=p1.y+firstU*(p2.y-p1.y);offset=shortProjVertex.xy;degenerate=true;}else{float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;}return degenerate;}void squareCap(out vec2 offset,out float round,in bool isRound,in vec2 nextP,in float turnDir,in float direction){round=0.0;vec2 dirVect=e-nextP;vec2 firstNormal=normalize(dirVect);vec2 secondNormal=vec2(turnDir*firstNormal.y*direction,-turnDir*firstNormal.x*direction);vec2 hypotenuse=normalize(firstNormal-secondNormal);vec2 normal=vec2(turnDir*hypotenuse.y*direction,-turnDir*hypotenuse.x*direction);float length=sqrt(c*c*2.0);offset=normal*length;if(isRound){round=1.0;}} void main(void){bool degenerate=false;float direction=float(sign(g));mat4 offsetMatrix=i*j;vec2 offset;vec4 projPos=h*vec4(e,0.0,1.0);bool round=nearlyEquals(mod(g,2.0),0.0);a=0.0;c=k/2.0;b=projPos.xy;if(nearlyEquals(mod(g,3.0),0.0)||nearlyEquals(mod(g,17.0),0.0)){alongNormal(offset,f,1.0,direction);}else if(nearlyEquals(mod(g,5.0),0.0)||nearlyEquals(mod(g,13.0),0.0)){alongNormal(offset,d,-1.0,direction);}else if(nearlyEquals(mod(g,23.0),0.0)){miterUp(offset,a,round,direction);}else if(nearlyEquals(mod(g,19.0),0.0)){degenerate=miterDown(offset,projPos,offsetMatrix,direction);}else if(nearlyEquals(mod(g,7.0),0.0)){squareCap(offset,a,round,f,1.0,direction);}else if(nearlyEquals(mod(g,11.0),0.0)){squareCap(offset,a,round,d,-1.0,direction);}if(!degenerate){vec4 offsets=offsetMatrix*vec4(offset,0.0,0.0);gl_Position=projPos+offsets;}else{gl_Position=vec4(offset,0.0,1.0);}}"}e(Ba,ea);var Xa=new Ba;function Va(t,e){this.B=t.getUniformLocation(e,"n"),this.oa=t.getUniformLocation(e,"k"),this.R=t.getUniformLocation(e,"l"),this.c=t.getUniformLocation(e,"j"),this.f=t.getUniformLocation(e,"i"),this.a=t.getUniformLocation(e,"m"),this.ra=t.getUniformLocation(e,"p"),this.i=t.getUniformLocation(e,"h"),this.I=t.getUniformLocation(e,"o"),this.g=t.getAttribLocation(e,"g"),this.o=t.getAttribLocation(e,"d"),this.l=t.getAttribLocation(e,"f"),this.b=t.getAttribLocation(e,"e")}function Wa(t,e){ha.call(this,0,e),this.v=null,this.u=[],this.j=[],this.c={strokeColor:null,lineCap:void 0,lineDash:null,lineDashOffset:void 0,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0,s:!1}}function Za(t,e,o,i){for(var r=t.a.length,n=t.b.length,s="bevel"===t.c.lineJoin?0:"miter"===t.c.lineJoin?1:2,a="butt"===t.c.lineCap?0:"square"===t.c.lineCap?1:2,p=Oa(e,o,i),h=n,l=1,u=0;uo&&(this.i.push(o),this.f.push(e),this.c.s)&&(this.j.push(o),this.c.s=!1)},r.Db=function(){this.l=new da(this.a),this.o=new da(this.b),this.i.push(this.b.length),!this.j.length&&0=l;){var u=this.i[h];o[U(this.f[h]).toString()]&&(s!==p&&(la(t,e,s,p),t.clear(t.DEPTH_BUFFER_BIT)),p=u),h--,s=u}s!==p&&(la(t,e,s,p),t.clear(t.DEPTH_BUFFER_BIT)),s=p=l}i||(t.disable(t.DEPTH_TEST),t.clear(t.DEPTH_BUFFER_BIT),t.depthMask(n),t.depthFunc(r))},r.ve=function(t,e,o,i,r){for(var n,s=this.i.length-2,a=this.i[s+1],p=this.j.length-1;0<=p;--p)for(qa(this,t,(h=this.u[p])[0],h[1],h[2]),n=this.j[p];0<=s&&this.i[s]>=n;){var h=this.i[s],l=this.f[s];if(void 0===o[U(l).toString()]&&l.V()&&(void 0===r||Ot(r,l.V().G()))&&(t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT),la(t,e,h,a),a=i(l)))return a;s--,a=h}},r.Ma=function(t,e){t=e.f,this.c.lineCap=void 0!==t?t:"round",t=e.i,this.c.lineDash=t||ca,t=e.g,this.c.lineDashOffset=t||0,t=e.j,this.c.lineJoin=void 0!==t?t:"round",t=!((t=e.a)instanceof CanvasGradient||t instanceof CanvasPattern)&&vo(t).map(function(t,e){return 3!=e?t/255:t})||fa;var o=void 0!==(o=e.c)?o:1;e=void 0!==(e=e.o)?e:10,this.c.strokeColor&&Z(this.c.strokeColor,t)&&this.c.lineWidth===o&&this.c.miterLimit===e||(this.c.s=!0,this.c.strokeColor=t,this.c.lineWidth=o,this.c.miterLimit=e,this.u.push([t,o,e]))};var Ja=3,_a=5,$a=7,Qa=11,tp=13,ep=17,op=19,ip=23;function rp(){this.b="precision mediump float;uniform vec4 e;uniform float f;void main(void){gl_FragColor=e;float alpha=e.a*f;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}"}e(rp,ta);var np=new rp;function sp(){this.b="attribute vec2 a;uniform mat4 b;uniform mat4 c;uniform mat4 d;void main(void){gl_Position=b*vec4(a,0.0,1.0);}"}e(sp,ea);var ap=new sp;function pp(t,e){this.B=t.getUniformLocation(e,"e"),this.c=t.getUniformLocation(e,"d"),this.f=t.getUniformLocation(e,"c"),this.a=t.getUniformLocation(e,"f"),this.i=t.getUniformLocation(e,"b"),this.b=t.getAttribLocation(e,"a")}function hp(t){this.a=void 0!==(t=t||{}).color?t.color:null,this.f=t.lineCap,this.i=void 0!==t.lineDash?t.lineDash:null,this.g=t.lineDashOffset,this.j=t.lineJoin,this.o=t.miterLimit,this.c=t.width,this.b=void 0}function lp(t){this.b=this.a=this.i=void 0,this.f=void 0===t||t,this.c=0}function up(t){var e,o,i=t.b;i&&(e=i.next,o=i.ub,e&&(e.ub=o),o&&(o.next=e),t.b=e||o,t.i===t.a?(t.b=void 0,t.i=void 0,t.a=void 0):t.i===i?t.i=t.b:t.a===i&&(t.a=o?t.b.ub:t.b),t.c--)}function cp(t){if(t.b=t.i,t.b)return t.b.data}function fp(t){if(t.b&&t.b.next)return t.b=t.b.next,t.b.data}function yp(t){if(t.b&&t.b.next)return t.b.next.data}function gp(t){if(t.b&&t.b.ub)return t.b=t.b.ub,t.b.data}function dp(t){if(t.b&&t.b.ub)return t.b.ub.data}function vp(t){if(t.b)return t.b.data}(r=hp.prototype).clone=function(){var t=this.a;return new hp({color:t&&t.slice?t.slice():t||void 0,lineCap:this.f,lineDash:this.i?this.i.slice():void 0,lineDashOffset:this.g,lineJoin:this.j,miterLimit:this.o,width:this.c})},r.No=function(){return this.a},r.Vk=function(){return this.f},r.Oo=function(){return this.i},r.Wk=function(){return this.g},r.Xk=function(){return this.j},r.bl=function(){return this.o},r.Po=function(){return this.c},r.Qo=function(t){this.a=t,this.b=void 0},r.aq=function(t){this.f=t,this.b=void 0},r.setLineDash=function(t){this.i=t,this.b=void 0},r.bq=function(t){this.g=t,this.b=void 0},r.cq=function(t){this.j=t,this.b=void 0},r.gq=function(t){this.o=t,this.b=void 0},r.jq=function(t){this.c=t,this.b=void 0},lp.prototype.concat=function(t){var e;t.b&&(this.b?(e=this.b.next,this.b.next=t.i,t.i.ub=this.b,e.ub=t.a,t.a.next=e,this.c+=t.c):(this.b=t.b,this.i=t.i,this.a=t.a,this.c=t.c),t.b=void 0,t.i=void 0,t.a=void 0,t.c=0)};var bp,mp={$d:function(){}};function wp(t,e,o){var i=t[e];t[e]=t[o],t[o]=i}function xp(t,e){return t=t.ca&&e.ia>=t.da}function Ip(t){return{children:t,height:1,ib:!0,ca:1/0,da:1/0,$:-1/0,ia:-1/0}}function Np(t,e,o,i,r){for(var n,s=[e,o];s.length;)(o=s.pop())-(e=s.pop())<=i||(n=e+Math.ceil((o-e)/i/2)*i,bp(t,n,e,o,r),s.push(e,n,n,o))}function Fp(t){this.a=mp.$d(t),this.b={}}function kp(t,e,o){var i=t.b[U(o)];St([i.ca,i.da,i.$,i.ia],e)||(t.remove(o),t.Ca(e,o))}function Dp(t){return t.a.all().map(function(t){return t.value})}function Op(t,e){return t.a.search({ca:e[0],da:e[1],$:e[2],ia:e[3]}).map(function(t){return t.value})}function Up(t,e,o,i){return Gp(Op(t,e),o,i)}function Gp(t,e,o){for(var i,r=0,n=t.length;rn&&(n=e[c],u=e[c+1]),l=y}else for(l=s=Yp(t,e[c=e.length-o],e[c+1],a++),n=e[c],u=e[c+1],c-=o,f=0;f<=c;c-=o)y=Yp(t,e[c],e[c+1],a++),h.push(Hp(l,y,i)),p.push([Math.min(l.x,y.x),Math.min(l.y,y.y),Math.max(l.x,y.x),Math.max(l.y,y.y)]),e[c]>n&&(n=e[c],u=e[c+1]),l=y;return h.push(Hp(y,s,i)),p.push([Math.min(l.x,y.x),Math.min(l.y,y.y),Math.max(l.x,y.x),Math.max(l.y,y.y)]),r.load(p,h),[n,u]}function Wp(t,e,o){var i=cp(t),r=i,n=fp(t),s=!1;do{var a=o?ya(n.W.x,n.W.y,r.W.x,r.W.y,r.aa.x,r.aa.y):ya(r.aa.x,r.aa.y,r.W.x,r.W.y,n.W.x,n.W.y)}while(void 0===a?(qp(r,n,t,e),s=!0,n===i&&(i=yp(t)),n=r,gp(t)):r.W.Fb!==a&&(r.W.Fb=a,s=!0),r=n,n=fp(t),r!==i);return s}function Zp(t,e,o,i,r){var n=t.b.length,s=cp(e),a=dp(e),p=s,h=fp(e),l=yp(e),u=!1;do{var c,f=p.aa,y=p.W,g=h.W}while(!1===y.Fb&&(c=r?Qp(l.W,g,y,f,a.aa):Qp(a.aa,f,y,g,l.W),!i&&_p({aa:f,W:g},o).length||!c||Jp(f,y,g,o,!0).length||!i&&!1!==f.Fb&&!1!==g.Fb&&Vr([a.aa.x,a.aa.y,f.x,f.y,y.x,y.y,g.x,g.y,l.W.x,l.W.y],0,10,2)!==!r||(t.b[n++]=f.hb,t.b[n++]=y.hb,t.b[n++]=g.hb,qp(p,h,e,o),h===s&&(s=l),u=!0)),a=dp(e),p=vp(e),h=fp(e),l=yp(e),p!==s&&3(o.y-i.y)*(e.x-i.x),r=(r.x-i.x)*(e.y-i.y)<(r.y-i.y)*(e.x-i.x),t=(t.x-e.x)*(i.y-e.y)>(t.y-e.y)*(i.x-e.x),o=(o.x-e.x)*(i.y-e.y)<(o.y-e.y)*(i.x-e.x),e=e.Fb?o||t:o&&t,i.Fb?r||n:r&&n)&&e}function th(){}function eh(t,e,o){this.f=e,this.g=t,this.c=o,this.a={}}function oh(t,e){var o,i=[];for(o in t.a){var r,n=t.a[o];for(r in n)i.push(n[r].Eb(e))}return function(){for(var t,e=i.length,o=0;othis.Hf;)this.jk(i,e),e--;this.Zj(o,i,e)},jk:function(t,e){var o=t[e],i=o.children.length,r=this.fh;this.$j(o,r,i),i=this.ak(o,r,i),(i=Ip(o.children.splice(i,o.children.length-i))).height=o.height,i.ib=o.ib,Mp(o,this.wb),Mp(i,this.wb),e?t[e-1].children.push(i):this.hh(o,i)},hh:function(t,e){this.data=Ip([t,e]),this.data.height=t.height+1,this.data.ib=!1,Mp(this.data,this.wb)},ak:function(t,e,o){for(var i=s=1/0,r=e;r<=o-e;r++){var n,s,a=Pp(t,0,r,this.wb),p=Pp(t,r,o,this.wb),h=Math.max(0,Math.min(a.$,p.$)-Math.max(a.ca,p.ca))*Math.max(0,Math.min(a.ia,p.ia)-Math.max(a.da,p.da)),a=jp(a)+jp(p);hr&&(this.i.push(r),this.f.push(e),this.j.s)&&(this.c.push(r),this.j.s=!1),this.g.b.length>n&&Ha(this.g,e,n)},r.rc=function(t,e){var o=t.Bb(),i=t.qa();if(0=l;){var u=this.i[h];o[U(this.f[h]).toString()]&&(s!==p&&(la(t,e,s,p),t.clear(t.DEPTH_BUFFER_BIT)),p=u),h--,s=u}s!==p&&(la(t,e,s,p),t.clear(t.DEPTH_BUFFER_BIT)),s=p=l}i||(t.disable(t.DEPTH_TEST),t.clear(t.DEPTH_BUFFER_BIT),t.depthMask(n),t.depthFunc(r))},r.ve=function(t,e,o,i,r){for(var n,s=this.i.length-2,a=this.i[s+1],p=this.c.length-1;0<=p;--p){var h=this.u[p];for(t.uniform4fv(this.v.B,h),n=this.c[p];0<=s&&this.i[s]>=n;){var h=this.i[s],l=this.f[s];if(void 0===o[U(l).toString()]&&l.V()&&(void 0===r||Ot(r,l.V().G()))&&(t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT),la(t,e,h,a),a=i(l)))return a;s--,a=h}}},r.Ma=function(t,e){t=!((t=t?t.b:[0,0,0,0])instanceof CanvasGradient||t instanceof CanvasPattern)&&vo(t).map(function(t,e){return 3!=e?t/255:t})||ua,this.j.fillColor&&Z(t,this.j.fillColor)||(this.j.fillColor=t,this.j.s=!0,this.u.push(t)),e?this.g.Ma(null,e):this.g.Ma(null,new hp({color:[0,0,0,0],lineWidth:0}))},th.prototype.La=function(){},e(eh,$s),eh.prototype.b=function(t,e){var o=void 0!==t?t.toString():"0";return void 0===(t=this.a[o])&&(this.a[o]=t={}),void 0===(o=t[e])&&(o=new nh[e](this.g,this.f),t[e]=o),o},eh.prototype.i=function(){return Zt(this.a)},eh.prototype.La=function(t,e,o,i,r,n,s,a){for(var p=Object.keys(this.a).map(Number),h=(p.sort(G),0),l=p.length;h=t.l)break;++n}t.D!=(o=r+" "+i)&&(t.o.innerHTML=o,t.D=o),t.B!=e&&(t.o.style.width=e+"px",t.B=e),t.j||(t.c.style.display="",t.j=!0)}else t.j&&(t.c.style.display="none",t.j=!1)}Th.prototype.C=function(){return this.get(Rh)},Th.prototype.T=function(){Lh(this)},Th.prototype.I=function(t){this.set(Rh,t)};var Rh="units";function Ih(t){t=t||{},this.c=void 0,this.j=Nh,this.D=this.l=0,this.I=null,this.na=!1,this.T=void 0!==t.duration?t.duration:200;var e=void 0!==t.className?t.className:"ol-zoomslider",o=document.createElement("button"),i=(o.setAttribute("type","button"),o.className=e+"-thumb ol-unselectable",document.createElement("div"));i.className=e+" ol-unselectable ol-control",i.appendChild(o),this.o=new Ii(i),d(this.o,"pointerdown",this.yl,this),d(this.o,"pointermove",this.wl,this),d(this.o,"pointerup",this.xl,this),d(i,"click",this.vl,this),d(o,"click",to),To.call(this,{element:i,render:t.render||Fh})}e(Ih,To),Ih.prototype.ka=function(){$e(this.o),To.prototype.ka.call(this)};var Nh=0;function Fh(t){var e,o,i,r,n;t.frameState&&(this.na||(e=(r=this.element).offsetWidth,o=r.offsetHeight,n=r.firstElementChild,i=getComputedStyle(n),r=n.offsetWidth+parseFloat(i.marginRight)+parseFloat(i.marginLeft),n=n.offsetHeight+parseFloat(i.marginTop)+parseFloat(i.marginBottom),this.I=[r,n],o>1)],o))<0?p=r+1:(h=r,l=!a);a=(r=l?p:~p)<0?(o=(o-s[-r-2])/(s[-r-1]-s[-r-2]),s=nt(t[e+=(-r-2)*i],t[e+i],o),nt(t[e+1],t[e+i+1],o)):(s=t[e+r*i],t[e+r*i+1])}return n?(n[0]=s,n[1]=a,n):[s,a]}function Tl(t,e,o,i,r,n){if(o==e)return null;if(r>1)+1)*i-1]?o=n:e=n+1;if(r==(o=t[e*i-1]))return t.slice((e-1)*i,(e-1)*i+i);var s;for(n=(r-o)/(t[(e+1)*i-1]-o),o=[],s=0;s>>0):4294967296*(e>>>0)+(t>>>0)}function Qy(t,e){this.layers=t.Ag(ng,{},e)}function tg(t,e){this.x=t,this.y=e}function eg(t,e,o,i,r){this.properties={},this.extent=o,this.type=0,this.Cc=t,this.Ef=-1,this.ne=i,this.pe=r,t.Ag(og,this,e)}function og(t,e,o){if(1==t)e.id=o.Ka();else if(2==t)for(t=o.Ka()+o.ea;o.ea>3)?t.Gg():2===e?t.yp():3===e?t.up():4===e?t.Kp():5===e?t.Ka():6===e?t.ce():7===e?t.sp():null;return e}(o))}function ng(t,e,o){3===t&&(t=new Gy(o,o.Ka()+o.ea)).length&&(e[t.name]=t)}function sg(t,e,o,i,r){this.g=r,this.i=t,this.b=e,this.f=o,this.c=i}function ag(t){wl.call(this),t=t||{},this.defaultDataProjection=new qt({code:"",units:"tile-pixels"}),this.b=t.featureClass||sg,this.a=t.geometryName,this.i=t.layerName||"layer",this.c=t.layers||null}function pg(t,e,o){for(var i=0,r=0,n=t.length;r>1,p=-7,h=o?-1:1,l=t[e+(r=o?r-1:0)];for(r+=h,o=l&(1<<-p)-1,l>>=-p,p+=n;0>=-p,p+=i;0>3,n=this.ea;this.type=7&i,t(r,e,this),this.ea===n&&this.mq(i)}return e},yp:function(){var t=Uy(this.lc,this.ea,!0,23,4);return this.ea+=4,t},up:function(){var t=Uy(this.lc,this.ea,!0,52,8);return this.ea+=8,t},Ka:function(t){var e=this.lc,o=e[this.ea++],i=127&o;if(o<128)return i;if(i|=(127&(o=e[this.ea++]))<<7,o<128)return i;if(i|=(127&(o=e[this.ea++]))<<14,o<128)return i;if(i|=(127&(o=e[this.ea++]))<<21,o<128)return i;var o=i|(15&e[this.ea])<<28,i=t,e=this,t=e.lc,r=t[e.ea++],n=(112&r)>>4;if(r<128)return $y(o,n,i);if(n|=(127&(r=t[e.ea++]))<<3,r<128)return $y(o,n,i);if(n|=(127&(r=t[e.ea++]))<<10,r<128)return $y(o,n,i);if(n|=(127&(r=t[e.ea++]))<<17,r<128)return $y(o,n,i);if(n|=(127&(r=t[e.ea++]))<<24,r<128)return $y(o,n,i);if((r=t[e.ea++])<128)return $y(o,n|(1&r)<<31,i);throw Error("Expected varint not more than 10 bytes")},Kp:function(){return this.Ka(!0)},ce:function(){var t=this.Ka();return 1==t%2?(t+1)/-2:t/2},sp:function(){return!!this.Ka()},Gg:function(){for(var t=this.Ka()+this.ea,e=this.lc,o="",i=this.ea;i>>10&1023|55296),p=56320|1023&p),o+=String.fromCharCode(p),i+=h}return this.ea=t,o},mq:function(t){if((t&=7)===_y.c)for(;127>=3),r--,1===i||2===i)n+=t.ce(),s+=t.ce(),1===i&&(e&&a.push(e),e=[]),e.push(new tg(n,s));else{if(7!==i)throw Error("unknown command "+i);e&&e.push(e[0].clone())}return e&&a.push(e),a},eg.prototype.bbox=function(){var t=this.Cc;t.ea=this.Ef;for(var e=t.Ka()+t.ea,o=1,i=0,r=0,n=0,s=1/0,a=-1/0,p=1/0,h=-1/0;t.ea>=3),i--,1===o||2===o)(r+=t.ce())=this.me.length)throw Error("feature index out of bounds");return this.Cc.ea=this.me[t],t=this.Cc.Ka()+this.Cc.ea,new eg(this.Cc,t,this.extent,this.ne,this.pe)},By=Gy,fi.default={Bf:Qy,Wj:eg,Xj:By},fi.Bf=Qy,fi.Wj=eg,fi.Xj=By,(r=sg.prototype).get=function(t){return this.c[t]},r.Bb=function(){return this.f},r.G=function(){return this.a||(this.a="Point"===this.i?wt(this.b):xt(this.b,0,this.b.length,2)),this.a},r.Wn=function(){return this.g},r.ec=function(){return this.b},r.ga=sg.prototype.ec,r.V=function(){return this},r.Xn=function(){return this.c},r.Vd=sg.prototype.V,r.qa=function(){return 2},r.Lc=Y,r.U=function(){return this.i},e(ag,wl),(r=ag.prototype).U=function(){return"arraybuffer"},r.Oa=function(t,e){var o,i=this.c,r=(t=new mp.Dd(t),t=new mp.xf.Bf(t),[]),n=this.b;for(o in t.layers)if(!i||-1!=i.indexOf(o))for(var s,a,p,h,l,u,c,f,y,g=t.layers[o],d=0,v=g.length;d>=5;e+=n+=String.fromCharCode(r+63)}return e}function Dg(t,e){e=e||1e5;for(var o=[],i=0,r=0,n=0,s=t.length;n>1):r>>1;for(t=0,i=o.length;t=e[0]||t[1]<=e[1]&&t[3]>=e[1]||Et(t,this.sb,this))},r.ob=function(t){var e,o=this.a,i=t.slice();for(i[o]=i[0]+(this.A[o]-this.A[0]),e=1;eg[2])&&(c=e*Math.ceil((g[0]-c)/e),f=[f[0]+c,f[1],f[2]+c,f[3]]),c=this.S[0],g=this.S[1],e=-1,i=Math.pow(this.Jb*d,2),r=[],n=[],d=0,o=y0.length;dw.width?w.width-A:R),O=M+E>w.height?w.height-E:M;e.drawImage(w,A,E,F,O,N,T,F*o,O*o),1!=P&&(e.globalAlpha=I),1==C&&!j||e.setTransform.apply(e,g)}++c;break;case 5:for(f=N[1],m=N[2],S=N[3],M=N[4]*o,P=N[5]*o,j=N[6],C=N[7]*o,w=N[8],x=N[9],(T=N[10])&&(j+=r);fthis.c&&(this.c=this.i.lineWidth,this.f=null)},e(Y0,O0),(r=Y0.prototype).Zb=function(t,e){var o,i=this.i,r=i.strokeStyle;void 0===i.fillStyle&&void 0===r||(q0(this,t),G0(this,e),this.b.push([9,bo(Os)]),void 0!==i.strokeStyle&&this.b.push([10,i.strokeStyle,i.lineWidth,i.lineCap,i.lineJoin,i.miterLimit,i.lineDash,i.lineDashOffset,!0,1]),o=t.ga(),r=this.coordinates.length,U0(this,o,0,o.length,t.qa(),!1,!1),this.a.push(t=[1],r=[2,r]),this.b.push(t,r),this.b.push(t=[7]),void 0!==i.fillStyle&&this.a.push(t),void 0!==i.strokeStyle&&(this.a.push(i=[12]),this.b.push(i)),V0(this,e))},r.rc=function(t,e){var o=this.i,o=(q0(this,t),G0(this,e),this.b.push([9,bo(Os)]),void 0!==o.strokeStyle&&this.b.push([10,o.strokeStyle,o.lineWidth,o.lineCap,o.lineJoin,o.miterLimit,o.lineDash,o.lineDashOffset,!0,1]),t.Bb());H0(this,t.ec(),0,o,t.qa()),V0(this,e)},r.pc=function(t,e){var o=this.i,i=o.strokeStyle;if(void 0!==o.fillStyle||void 0!==i){q0(this,t),G0(this,e),this.b.push([9,bo(Os)]),void 0!==o.strokeStyle&&this.b.push([10,o.strokeStyle,o.lineWidth,o.lineCap,o.lineJoin,o.miterLimit,o.lineDash,o.lineDashOffset,!0,1]),o=t.c,i=Il(t),t=t.qa();for(var r=0,n=0,s=o.length;nthis.c&&(this.c=o.lineWidth,this.f=null)):(o.strokeStyle=void 0,o.lineCap=void 0,o.lineDash=null,o.lineDashOffset=void 0,o.lineJoin=void 0,o.lineWidth=void 0,o.miterLimit=void 0)},e(J0,O0),J0.prototype.yc=function(t,e,o,i,r,n){var s,a;""!==this.Ia&&this.g&&(this.i||this.f)&&(this.i&&(r=this.i,(s=this.S)&&s.fillStyle==r.fillStyle||(a=[9,r.fillStyle],this.a.push(a),this.b.push(a),s?s.fillStyle=r.fillStyle:this.S={fillStyle:r.fillStyle})),this.f&&(r=this.f,(s=this.D)&&s.lineCap==r.lineCap&&s.lineDash==r.lineDash&&s.lineDashOffset==r.lineDashOffset&&s.lineJoin==r.lineJoin&&s.lineWidth==r.lineWidth&&s.miterLimit==r.miterLimit&&s.strokeStyle==r.strokeStyle||(a=[10,r.strokeStyle,r.lineWidth,r.lineCap,r.lineJoin,r.miterLimit,r.lineDash,r.lineDashOffset,!1,1],this.a.push(a),this.b.push(a),s?(s.lineCap=r.lineCap,s.lineDash=r.lineDash,s.lineDashOffset=r.lineDashOffset,s.lineJoin=r.lineJoin,s.lineWidth=r.lineWidth,s.miterLimit=r.miterLimit,s.strokeStyle=r.strokeStyle):this.D={lineCap:r.lineCap,lineDash:r.lineDash,lineDashOffset:r.lineDashOffset,lineJoin:r.lineJoin,lineWidth:r.lineWidth,miterLimit:r.miterLimit,strokeStyle:r.strokeStyle})),r=this.g,(s=this.C)&&s.font==r.font&&s.textAlign==r.textAlign&&s.textBaseline==r.textBaseline||(a=[11,r.font,r.textAlign,r.textBaseline],this.a.push(a),this.b.push(a),s?(s.font=r.font,s.textAlign=r.textAlign,s.textBaseline=r.textBaseline):this.C={font:r.font,textAlign:r.textAlign,textBaseline:r.textBaseline}),G0(this,n),t=[5,r=this.coordinates.length,t=U0(this,t,e,o,i,!1,!1),this.Ia,this.j,this.o,this.v,this.u,!!this.i,!!this.f,this.l],this.a.push(t),this.b.push(t),V0(this,n))},J0.prototype.Cb=function(t){var e,o,i,r,n,s,a,p,h;t?((o=t.Fa())?(o=Mo((o=o.b)||Os),this.i?this.i.fillStyle=o:this.i={fillStyle:o}):this.i=null,(s=t.Ga())?(o=s.a,i=s.f,r=s.i,a=s.g,p=s.j,n=s.c,s=s.o,i=void 0!==i?i:"round",r=r?r.slice():Us,a=void 0!==a?a:0,p=void 0!==p?p:"round",n=void 0!==n?n:1,s=void 0!==s?s:10,o=Mo(o||Gs),this.f?((h=this.f).lineCap=i,h.lineDash=r,h.lineDashOffset=a,h.lineJoin=p,h.lineWidth=n,h.miterLimit=s,h.strokeStyle=o):this.f={lineCap:i,lineDash:r,lineDashOffset:a,lineJoin:p,lineWidth:n,miterLimit:s,strokeStyle:o}):this.f=null,e=t.a,o=t.i,i=t.c,r=t.o,n=t.f,s=t.b,a=t.Na(),p=t.g,h=t.j,t=void 0!==e?e:"10px sans-serif",p=void 0!==p?p:"center",h=void 0!==h?h:"middle",this.g?((e=this.g).font=t,e.textAlign=p,e.textBaseline=h):this.g={font:t,textAlign:p,textBaseline:h},this.Ia=void 0!==a?a:"",this.j=void 0!==o?o:0,this.o=void 0!==i?i:0,this.l=void 0!==r&&r,this.v=void 0!==n?n:0,this.u=void 0!==s?s:1):this.Ia=""},e(_0,$s);var $0={0:[[!0]]};function Q0(t,e,o){var i,r=Math.floor(t.length/2);if(r<=e)for(i=r;it.$&&(t.$=i.$),i.dat.ia&&(t.ia=i.ia)):t[e][o]=i:(t[e]={},t[e][o]=i)}function lv(t,e,o,i,r,n,s,a,p,h){for(var l,u=U(e).toString(),c=(u in t.wantedTiles||(t.wantedTiles[u]={}),t.wantedTiles[u]),f=(t=t.tileQueue,o.minZoom),y=s;f<=y;--y)for(var g,d=Ie(o,n,y,d),v=o.Da(y),b=d.ca;b<=d.$;++b)for(l=d.da;l<=d.ia;++l)s-y<=a?(0==(g=e.Nc(y,b,l,i,r)).getState()&&(c[g.bb()]=!0,g.bb()in t.a||t.f([g,u,Ne(o,g.ta),v])),p&&p.call(h,g)):e.Ug(y,b,l,r)}function uv(t){iv.call(this,t),this.fa=ms()}function cv(t,e,o){var i=e.pixelRatio,r=e.size[0]*i,n=e.size[1]*i,s=e.viewState.rotation,a=Ft(o),p=kt(o),h=Ct(o);o=jt(o),Ps(e.coordinateToPixelTransform,a),Ps(e.coordinateToPixelTransform,p),Ps(e.coordinateToPixelTransform,h),Ps(e.coordinateToPixelTransform,o),t.save(),Bs(t,-s,r/2,n/2),t.beginPath(),t.moveTo(a[0]*i,a[1]*i),t.lineTo(p[0]*i,p[1]*i),t.lineTo(h[0]*i,h[1]*i),t.lineTo(o[0]*i,o[1]*i),t.clip(),Bs(t,s,r/2,n/2)}function fv(t,e,o,i,r){var n,s,a,p=t.a;oo(p,e)&&(n=i.size[0]*i.pixelRatio,s=i.size[1]*i.pixelRatio,Bs(o,-(a=i.viewState.rotation),n/2,s/2),t=r||yv(t,i,0),p.b(new Ds(e,new Vs(o,i.pixelRatio,i.extent,t,i.viewState.rotation),i,o,null)),Bs(o,a,n/2,s/2))}function yv(t,e,o){var i=e.viewState,r=e.pixelRatio,n=r/i.resolution;return js(t.fa,r*e.size[0]/2,r*e.size[1]/2,n,-n,-i.rotation,-i.center[0]+o,-i.center[1])}function gv(t,e){return U(t)-U(e)}function dv(t,e){return(t=.5*t/e)*t}function vv(t,e,o,i,r,n){var s,a,p=!1;return(s=o.Y())&&(2==(a=s.Ye())||3==a?s.Bj(r,n):(0==a&&s.load(),s.Nh(r,n),p=!0)),(r=(0,o.Za)(e))&&(i=r.Vd(i),(0,bv[i.U()])(t,i,o,e)),p}e(iv,io),iv.prototype.Ea=Y,iv.prototype.Ue=fr,iv.prototype.Nf=function(o,i,r){return function(e,t){return Cm(o,i,e,t,function(t){r[e]||(r[e]={}),r[e][t.ta.toString()]=t})}},iv.prototype.na=function(t){2===t.target.getState()&&nv(this)},e(uv,iv),uv.prototype.u=function(t,e,o,i){if(this.Ea(t,e,0,cr,this))return o.call(i,this.a,null)},uv.prototype.ef=function(t,e,o,i){fv(this,"postcompose",t,e,i)};var bv={Point:function(t,e,o,i){var r=o.Y();if(r){if(2!=r.Ye())return;var n=t.b(o.Ba(),"Image");n.Ub(r),n.qc(e,i)}(r=o.Na())&&((t=t.b(o.Ba(),"Text")).Cb(r),t.yc(e.ga(),0,2,2,e,i))},LineString:function(t,e,o,i){var r,n=o.Ga();n&&((r=t.b(o.Ba(),"LineString")).Ma(null,n),r.mc(e,i)),(n=o.Na())&&((t=t.b(o.Ba(),"Text")).Cb(n),t.yc(jl(e),0,2,2,e,i))},Polygon:function(t,e,o,i){var r,n=o.Fa(),s=o.Ga();(n||s)&&((r=t.b(o.Ba(),"Polygon")).Ma(n,s),r.rc(e,i)),(n=o.Na())&&((t=t.b(o.Ba(),"Text")).Cb(n),t.yc(zr(e),0,2,2,e,i))},MultiPoint:function(t,e,o,i){var r=o.Y();if(r){if(2!=r.Ye())return;var n=t.b(o.Ba(),"Image");n.Ub(r),n.oc(e,i)}(r=o.Na())&&((t=t.b(o.Ba(),"Text")).Cb(r),o=e.ga(),t.yc(o,0,o.length,e.qa(),e,i))},MultiLineString:function(t,e,o,i){var r,n=o.Ga();n&&((r=t.b(o.Ba(),"LineString")).Ma(null,n),r.nc(e,i)),(n=o.Na())&&((t=t.b(o.Ba(),"Text")).Cb(n),o=Cl(e),t.yc(o,0,o.length,2,e,i))},MultiPolygon:function(t,e,o,i){var r,n=o.Fa(),s=o.Ga();(s||n)&&((r=t.b(o.Ba(),"Polygon")).Ma(n,s),r.pc(e,i)),(n=o.Na())&&((t=t.b(o.Ba(),"Text")).Cb(n),o=Rl(e),t.yc(o,0,o.length,2,e,i))},GeometryCollection:function(t,e,o,i){for(var r=0,n=(e=e.a).length;rp[2];)l=yv(this,t,l=h*++m),u.La(y,r,l,a,n),s-=h;l=yv(this,t,0)}Bs(y,a,v/2,b/2),y!=o&&(fv(this,"render",y,t,l),o.drawImage(y.canvas,-g,-d),y.translate(-g,-d)),y.globalAlpha=f}c&&o.restore(),this.ef(o,t,e,l)},mv.prototype.Ea=function(t,e,o,i,r){var n,s;if(this.f)return n=this.a,s={},this.f.Ea(t,e.viewState.resolution,e.viewState.rotation,o,{},function(t){var e=U(t).toString();if(!(e in s))return s[e]=!0,i.call(r,t,n)})},mv.prototype.D=function(){nv(this)},mv.prototype.sd=function(t){function e(t){var e,o=t.Lc();if(o?e=o.call(t,n):(o=p.f)&&(e=o(t,n)),e){if(o=!1,Array.isArray(e))for(var i=0,r=e.length;it.ad:r<=t.ad),t.l?(r=e.coordinate,i=t.j.V(),t.g===Hv?o=t.a:t.g===Jv?(o=(o=t.a[0])[o.length-1],Wv(t,e)&&(r=t.l.slice())):o=(o=t.a)[o.length-1],o[0]=r[0],o[1]=r[1],t.Za(t.a,i),t.B&&t.B.V().ma(r),i instanceof w&&t.g!==Jv?(t.C||(t.C=new x(new S(null))),r=i.Ch(0),(e=t.C.V()).ba(r.ja,r.ga())):t.I&&(e=t.C.V()).ma(t.I),Yv(t)):(e=e.coordinate.slice(),t.B?t.B.V().ma(e):(t.B=new x(new m(e)),Yv(t))),!0}function Wv(t,e){var o=!1;if(t.j){var i=!1,r=[t.l];if(t.g===qv?i=t.a.length>t.Sa:t.g===Jv&&(i=t.a[0].length>t.Sa,r=[t.a[0][0],t.a[0][t.a[0].length-2]]),i)for(var i=e.map,n=0,s=r.length;n=t.va&&(t.u?i.pop():o=!0),i.push(e.slice()),t.Za(i,r)):t.g===Jv&&((i=t.a[0]).length>=t.va&&(t.u?i.pop():o=!0),i.push(e.slice()),o&&(t.l=i[0]),t.Za(t.a,r)),Yv(t),o&&t.Pd()}function zv(t){t.l=null;var e=t.j;return e&&(t.j=null,t.B=null,t.C=null,t.pa.ha().clear(!0)),e}function Yv(t){var e=[];t.j&&e.push(t.j),t.C&&e.push(t.C),t.B&&e.push(t.B),(t=t.pa.ha()).clear(!0),t.cd(e)}e(Lv,ro),(r=Lv.prototype).Ea=Y,r.ya=function(){return this.j},r.xa=function(){return this.D},r.za=function(){return this.c},r.getState=function(){return this.na},r.sa=function(){this.s()},r.ua=function(t){this.j=Rv(t),this.s()},e(a,Lv),(r=a.prototype).yb=function(t){var e,o=U(t).toString();Fv(this,o,t)&&(Nv(this,o,t),(e=t.V())?(o=e.G(),this.a&&this.a.Ca(o,t)):this.g[o]=t,this.b(new Ov("addfeature",t))),this.s()},r.cd=function(t){kv(this,t),this.s()},r.clear=function(t){if(t){for(var e in this.v)this.v[e].forEach(qe);this.f||(this.v={},this.o={},this.l={})}else if(this.a)for(var o in this.a.forEach(this.Ig,this),this.g)this.Ig(this.g[o]);this.f&&this.f.clear(),this.a&&this.a.clear(),this.R.clear(),this.g={},this.b(new Ov("clear")),this.s()},r.sh=function(t,e){return this.a?this.a.forEach(t,e):this.f?this.f.forEach(t,e):void 0},r.$b=function(t,e,o){return this.a?Up(this.a,t,e,o):this.f?this.f.forEach(e,o):void 0},r.th=function(e,o,i){return this.$b(e,function(t){if(t.V().Xa(e)&&(t=o.call(i,t)))return t})},r.Ah=function(){return this.f},r.Xe=function(){var t;return this.f?t=this.f.a:this.a&&(t=Dp(this.a),Zt(this.g)||X(t,Wt(this.g))),t},r.zh=function(t){var e,o,i=[];return e=t,o=function(t){i.push(t)},this.$b([e[0],e[1],e[0],e[1]],function(t){if(t.V().sb(e))return o.call(void 0,t)}),i},r.Uf=function(t){return Op(this.a,t)},r.vh=function(t,e){var i=t[0],r=t[1],n=null,s=[NaN,NaN],a=1/0,p=[-1/0,-1/0,1/0,1/0],h=e||cr;return Up(this.a,p,function(t){var e,o;h(t)&&(e=t.V(),o=a,(a=e.Kb(i,r,s,a))o&&(t.index+=r)})}function Mb(t,e,o){Qe.call(this,t),this.features=e,this.mapBrowserEvent=o}function Pb(t){var e,o;pn.call(this,{handleEvent:Ab}),this.C=(t=t||{}).condition||vn,this.D=t.addCondition||fr,this.B=t.removeCondition||fr,this.I=t.toggleCondition||mn,this.l=t.multi||!1,this.o=t.filter||cr,this.j=t.hitTolerance||0,this.g=new s({source:new a({useSpatialIndex:!1,features:t.features,wrapX:t.wrapX}),style:t.style||(X((e=Qh()).Polygon,e.LineString),X(e.GeometryCollection,e.LineString),function(t){return t.V()?e[t.V().U()]:null}),updateWhileAnimating:!0,updateWhileInteracting:!0}),t=t.layers?"function"==typeof t.layers?t.layers:(o=t.layers,function(t){return D(o,t)}):cr,this.u=t,this.a={},d(t=this.g.ha().f,"add",this.Fn,this),d(t,"remove",this.Jn,this)}function Ab(t){if(!this.C(t))return!0;var o=this.D(t),i=this.B(t),r=this.I(t),e=!o&&!i&&!r,n=t.map,s=this.g.ha().f,a=[],p=[];if(e){for(Vt(this.a),n.we(t.pixel,function(t,e){if(this.o(t,e))return p.push(t),t=U(t),this.a[t]=e,!this.l}.bind(this),{layerFilter:this.u,hitTolerance:this.j}),e=s.dc()-1;0<=e;--e){var n=s.item(e),h=p.indexOf(n);-1e.v),g))Math.abs(o[0]-r[0])<=Math.abs(o[1]-r[1])?(y=[(i[0]+r[0])/2,(i[1]+r[1])/2],f=e.a(y),u=[(n[0]+o[0])/2,(n[1]+o[1])/2],c=e.a(u),t(e,o,i,y,u,s,a,f,c,l-1),t(e,u,y,r,n,c,f,p,h,l-1)):(y=[(o[0]+i[0])/2,(o[1]+i[1])/2],f=e.a(y),u=[(r[0]+n[0])/2,(r[1]+n[1])/2],c=e.a(u),t(e,o,y,u,n,s,f,c,h,l-1),t(e,y,i,r,u,f,a,p,c,l-1));else{if(y){if(!e.l)return;e.o=!0}e.c.push({source:[s,p,h],target:[o,r,n]}),e.c.push({source:[s,a,p],target:[o,i,r]})}}}(this,t,e,i,o,r,p,h,l,10),this.o&&(n=1/0,this.c.forEach(function(t){n=Math.min(n,t.source[0][0],t.source[1][0],t.source[2][0])}),this.c.forEach(function(t){var e;Math.max(t.source[0][0],t.source[1][0],t.source[2][0])-n>this.b/2&&((e=[[t.source[0][0],t.source[0][1]],[t.source[1][0],t.source[1][1]],[t.source[2][0],t.source[2][1]]])[0][0]-n>this.b/2&&(e[0][0]-=this.b),e[1][0]-n>this.b/2&&(e[1][0]-=this.b),e[2][0]-n>this.b/2&&(e[2][0]-=this.b),Math.max(e[0][0],e[1][0],e[2][0])-Math.min(e[0][0],e[1][0],e[2][0])r[0]||t[1]<0||t[1]>r[1])&&(this.f||(this.f=Po(1,1)),this.f.clearRect(0,0,1,1),this.f.drawImage(this.M.Y(),t[0],t[1],1,1,0,0,1,1),0<(r=this.f.getImageData(0,0,1,1).data)[3]))return o.call(i,this.a,r)}},e(pm,ys),pm.prototype.Fd=function(t){var e=null,o=t.U();return"canvas"===o?e=new Kb(this):"webgl"===o&&(e=new am(t,this)),e},e(hm,Zb),hm.prototype.sd=function(t,e){var o=t.pixelRatio,i=t.size,r=(s=t.viewState).projection,n=s.resolution,s=s.center,a=this.a,p=a.ha(),h=p.i,l=p.Ta(r),u=l.tc(n,this.T),c=l.Da(u),f=Math.round(n/c)||1,y=t.extent;if(Ut(y=void 0!==e.extent?Nt(y,e.extent):y))return!1;var g=Re(l,y,c),d=l.Pc(u),v=l.Da(u),b=pt(l.gb(u),l.j),d=bt(d[0]+g.ca*b[0]*v,d[1]+g.da*b[1]*v,d[0]+(g.$+1)*b[0]*v,d[1]+(g.ia+1)*b[1]*v,void 0),v=p.nb(o),m=((b={})[u]={},this.Nf(p,r,b)),w=this.l,x=this.va,S=!1;for(C=g.ca;C<=g.$;++C)for(L=g.da;L<=g.ia;++L){var M=p.Nc(u,C,L,o,r);3!=M.getState()||this.a.kd()||S0(M,2),lm(this,M)||(M=x0(M)),lm(this,M)?2==M.getState()&&(b[u][M.ta.toString()]=M,S||-1!=this.g.indexOf(M)||(S=!0)):Ce(l,M.ta,m,x,w)||(M=Le(l,M.ta,x,w))&&m(u+1,M)}if(C=(C=t.viewHints)[0]||C[1],!(this.f&&16t.highWaterMark}function jm(t){Lv.call(this,{attributions:t.attributions,extent:t.extent,logo:t.logo,projection:t.projection,state:t.state,wrapX:t.wrapX}),this.va=void 0!==t.opaque&&t.opaque,this.$a=void 0!==t.tilePixelRatio?t.tilePixelRatio:1,this.tileGrid=void 0!==t.tileGrid?t.tileGrid:null,this.a=new Em(t.cacheSize),this.o=[0,0],this.uc=""}function Cm(t,e,o,i,r){if(!(e=t.Wd(e)))return!1;for(var n,s,a=!0,p=i.ca;p<=i.$;++p)for(var h=i.da;h<=i.ia;++h)n=t.Sb(o,p,h),s=!1,(s=e.b.hasOwnProperty(n)?(s=2===(n=e.get(n)).getState())&&!1!==r(n):s)||(a=!1);return a}function Lm(t,e){t.uc!==e&&(t.uc=e,t.s())}function Rm(t,e,o){var i,r,n=void 0!==o?o:t.c;return o=t.Ta(n),t.u&&n.c&&(e=(i=e)[0],t=Ne(o,i),e=ft(n=Ge(n),t)?i:(i=Dt(n),t[0]+=i*Math.ceil((n[0]-t[0])/i),o.bg(t,e))),i=e[0],n=e[1],t=e[2],(o=!(o.minZoom>i||i>o.maxZoom)&&(!(o=(r=o.G())?Ie(o,r,i):o.a?o.a[i]:null)||_(o,n,t)))?e:null}function Im(t,e){Qe.call(this,t),this.tile=e}function Nm(t){jm.call(this,{attributions:t.attributions,cacheSize:t.cacheSize,extent:t.extent,logo:t.logo,opaque:t.opaque,projection:t.projection,state:t.state,tileGrid:t.tileGrid,tilePixelRatio:t.tilePixelRatio,wrapX:t.wrapX}),this.tileLoadFunction=t.tileLoadFunction,this.tileUrlFunction=this.Fc?this.Fc.bind(this):Pm,this.urls=null,t.urls?this.eb(t.urls):t.url&&this.jb(t.url),t.tileUrlFunction&&this.cb(t.tileUrlFunction)}function T(t){Nm.call(this,{attributions:t.attributions,cacheSize:t.cacheSize,extent:t.extent,logo:t.logo,opaque:t.opaque,projection:t.projection,state:t.state,tileGrid:t.tileGrid,tileLoadFunction:t.tileLoadFunction||Dm,tilePixelRatio:t.tilePixelRatio,tileUrlFunction:t.tileUrlFunction,url:t.url,urls:t.urls,wrapX:t.wrapX}),this.crossOrigin=void 0!==t.crossOrigin?t.crossOrigin:null,this.tileClass=t.tileClass||M0,this.g={},this.v={},this.Sa=t.reprojectionErrorThreshold,this.I=!1}function Fm(t,e,o,i,r,n,s){return r=(o=Rm(t,e=[e,o,i],n))?t.tileUrlFunction(o,r,n):void 0,(r=new t.tileClass(e,void 0!==r?0:4,void 0!==r?r:"",t.crossOrigin,t.tileLoadFunction)).key=s,d(r,"change",t.Li,t),r}function km(t,e,o,i,r,n){var s=t.Sb(e,o,i),a=t.uc;if(t.a.b.hasOwnProperty(s)){if((h=t.a.get(s)).key!=a){var p=h,h=Fm(t,e,o,i,r,n,a);if(0==p.getState()?h.i=p.i:h.i=p,h.i){e=h.i,o=h;do{if(2==e.getState()){e.i=null;break}}while(1!=e.getState()&&0==e.getState()?o.i=e.i:o=e,e=o.i)}t.a.replace(s,h)}}else h=Fm(t,e,o,i,r,n,a),t.a.set(s,h);return h}function Dm(t,e){t.Y().src=e}function j(t){this.B=void 0!==t.hidpi&&t.hidpi,T.call(this,{cacheSize:t.cacheSize,crossOrigin:"anonymous",opaque:!0,projection:v("EPSG:3857"),reprojectionErrorThreshold:t.reprojectionErrorThreshold,state:"loading",tileLoadFunction:t.tileLoadFunction,tilePixelRatio:this.B?2:1,wrapX:void 0===t.wrapX||t.wrapX}),this.R=void 0!==t.culture?t.culture:"en-us",this.C=void 0!==t.maxZoom?t.maxZoom:-1,this.f=t.key,this.l=t.imagerySet,wm("https://dev.virtualearth.net/REST/v1/Imagery/Metadata/"+this.l+"?uriScheme=https&include=ImageryProviders&key="+this.f,this.pa.bind(this),void 0,"jsonp")}(r=vm.prototype).sd=function(t,e){var o=this.a,i=o.i;return this.pa!=i&&(this.g.length=0,o=o.j,this.c||"vector"==o||(this.c=Po()),this.c)&&"vector"==o&&(this.c=null),this.pa=i,hm.prototype.sd.apply(this,arguments)},r.Of=function(t,e,o,i,r,n,s,a){var p=t,h=this.a,l=e.pixelRatio,u=e.viewState.projection,c=h.i,f=h.get(jv)||null,y=p.o;if(y.Nd||y.mf!=c||y.Kg!=f){for(var g=0,d=p.a.length;gTerms of Use
    '});function Um(t){var e=void 0!==(t=t||{}).projection?t.projection:"EPSG:3857",o=void 0!==t.tileGrid?t.tileGrid:De({extent:Ge(e),maxZoom:t.maxZoom,minZoom:t.minZoom,tileSize:t.tileSize});T.call(this,{attributions:t.attributions,cacheSize:t.cacheSize,crossOrigin:t.crossOrigin,logo:t.logo,opaque:t.opaque,projection:e,reprojectionErrorThreshold:t.reprojectionErrorThreshold,tileGrid:o,tileLoadFunction:t.tileLoadFunction,tilePixelRatio:t.tilePixelRatio,tileUrlFunction:t.tileUrlFunction,url:t.url,urls:t.urls,wrapX:void 0===t.wrapX||t.wrapX})}function C(t){this.C=t.account,this.B=t.map||"",this.f=t.config||{},this.l={},Um.call(this,{attributions:t.attributions,cacheSize:t.cacheSize,crossOrigin:t.crossOrigin,logo:t.logo,maxZoom:void 0!==t.maxZoom?t.maxZoom:18,minZoom:t.minZoom,projection:t.projection,state:"loading",wrapX:t.wrapX}),Gm(this)}function Gm(t){var e,o,i=JSON.stringify(t.f);t.l[i]?Bm(t,t.l[i]):(e="https://"+t.C+".cartodb.com/api/v1/map",t.B&&(e+="/named/"+t.B),(o=new XMLHttpRequest).addEventListener("load",t.Dl.bind(t,i)),o.addEventListener("error",t.Cl.bind(t)),o.open("POST",e),o.setRequestHeader("Content-type","application/json"),o.send(JSON.stringify(t.f)))}function Bm(t,e){t.jb("https://"+e.cdn_url.https+"/"+t.C+"/api/v1/map/"+e.layergroupid+"/{z}/{x}/{y}.png")}function L(t){a.call(this,{attributions:t.attributions,extent:t.extent,logo:t.logo,projection:t.projection,wrapX:t.wrapX}),this.resolution=void 0,this.distance=void 0!==t.distance?t.distance:20,this.features=[],this.geometryFunction=t.geometryFunction||function(t){return O((t=t.V())instanceof m,10),t},this.source=t.source,this.source.J("change",L.prototype.sa,this)}function Xm(t){if(void 0!==t.resolution){t.features.length=0;for(var e=vt(),o=t.distance*t.resolution,i=t.source.Xe(),r={},n=0,s=i.length;n>=1}return o.join("")}(e))}})),i.imageryProviders&&(p=we(v("EPSG:4326"),this.c),(t=i.imageryProviders.map(function(t){var e=t.attribution,n={};return t.coverageAreas.forEach(function(t){var e,o=t.zoomMin,i=Math.min(t.zoomMax,s);for(t=Bt([(t=t.bbox)[1],t[0],t[3],t[2]],p),e=o;e<=i;++e){var r=e.toString(),o=Ie(a,t,e);r in n?n[r].push(o):n[r]=[o]}}),new Be({html:e,tileRanges:n})})).push(Om),this.ua(t)),this.D=e,Iv(this,"ready"))},e(Um,T),e(C,Um),(r=C.prototype).Kk=function(){return this.f},r.tq=function(t){Xt(this.f,t),Gm(this)},r.Xp=function(t){this.f=t||{},Gm(this)},r.Dl=function(t,e){if(!(e=e.target).status||200<=e.status&&e.status<300){try{var o=JSON.parse(e.responseText)}catch(t){return void Iv(this,"error")}Bm(this,o),this.l[t]=o,Iv(this,"ready")}else Iv(this,"error")},r.Cl=function(){Iv(this,"error")},e(L,a),(r=L.prototype).$n=function(){return this.distance},r.ao=function(){return this.source},r.Yd=function(t,e,o){this.source.Yd(t,e,o),e!==this.resolution&&(this.clear(),this.resolution=e,Xm(this),this.cd(this.features))},r.Yp=function(t){this.distance=t,this.sa()},r.sa=function(){this.clear(),Xm(this),this.cd(this.features),a.prototype.sa.call(this)},e(Wm,$b),(r=Wm.prototype).co=function(){return this.v},r.Jc=function(t,e,o,i){if(void 0===this.f)return null;e=Qb(this,e),o=this.T?o:1;var r=this.M;if(r&&this.I==this.i&&r.resolution==e&&r.a==o&&yt(r.G(),t))return r;Xt(r={F:"image",FORMAT:"PNG32",TRANSPARENT:!0},this.v);var n=((t=t.slice())[0]+t[2])/2,s=(t[1]+t[3])/2,a=(1!=this.B&&(a=this.B*Dt(t)/2,p=this.B*It(t)/2,t[0]=n-a,t[1]=s-p,t[2]=n+a,t[3]=s+p),e/o),p=Math.ceil(Dt(t)/a),h=Math.ceil(It(t)/a);return t[0]=n-a*p/2,t[2]=n+a*p/2,t[1]=s-a*h/2,t[3]=s+a*h/2,this.l[0]=p,this.l[1]=h,n=t,s=this.l,a=o,i=i.mb.split(":").pop(),r.SIZE=s[0]+","+s[1],r.BBOX=n.join(","),r.BBOXSR=i,r.IMAGESR=i,r.DPI=Math.round(90*a),(n=(i=this.f).replace(/MapServer\/?$/,"MapServer/export").replace(/ImageServer\/?$/,"ImageServer/exportImage"))==i&&O(!1,50),r=Vm(n,r),this.M=new b0(t,e,o,this.j,r,this.R,this.g),this.I=this.i,d(this.M,"change",this.o,this),this.M},r.bo=function(){return this.g},r.eo=function(){return this.f},r.fo=function(t){this.M=null,this.g=t,this.s()},r.ho=function(t){t!=this.f&&(this.f=t,this.M=null,this.s())},r.io=function(t){Xt(this.v,t),this.M=null,this.s()},e(Zm,$b),(r=Zm.prototype).ko=function(){return this.g},r.Jc=function(t,e,o){e=Qb(this,e),o=this.T?o:1;var i,r,n,s,a,p,h,l,u=this.M;return u&&this.B==this.i&&u.resolution==e&&u.a==o&&yt(u.G(),t)||(1!=this.v&&Gt(t=t.slice(),this.v),l=[Dt(t)/e*o,It(t)/e*o],void 0!==this.I?(u=this.I,i=Lt(t),r=this.pa,n=Dt(t),s=It(t),a=l[0],p=l[1],h=.0254/this.l,l={OPERATION:this.va?"GETDYNAMICMAPOVERLAYIMAGE":"GETMAPIMAGE",VERSION:"2.0.0",LOCALE:"en",CLIENTAGENT:"ol.source.ImageMapGuide source",CLIP:"1",SETDISPLAYDPI:this.l,SETDISPLAYWIDTH:Math.round(l[0]),SETDISPLAYHEIGHT:Math.round(l[1]),SETVIEWSCALE:a*sOpenStreetMap contributors.'}),fi=(mp.df={},mp.df.Af=function(){},mp.df=mp.df||{});function $m(u){var c=!0;try{new ImageData(10,10)}catch(t){c=!1}return function(t){var e=t.buffers,o=t.meta,i=t.width,r=t.height,n=e.length,s=e[0].byteLength;if(t.imageOps){for(s=Array(n),t=0;tthis.fk;)this.Ed.shift().callback(null,null)},Qm.prototype.dh=function(){if(0===this.oe&&0Stamen Design, under CC BY 3.0.'}),_m],h1={terrain:{Lb:"jpg",opaque:!0},"terrain-background":{Lb:"jpg",opaque:!0},"terrain-labels":{Lb:"png",opaque:!1},"terrain-lines":{Lb:"png",opaque:!1},"toner-background":{Lb:"png",opaque:!0},toner:{Lb:"png",opaque:!0},"toner-hybrid":{Lb:"png",opaque:!1},"toner-labels":{Lb:"png",opaque:!1},"toner-lines":{Lb:"png",opaque:!1},"toner-lite":{Lb:"png",opaque:!0},watercolor:{Lb:"jpg",opaque:!0}},l1={terrain:{minZoom:4,maxZoom:18},toner:{minZoom:0,maxZoom:20},watercolor:{minZoom:1,maxZoom:16}};function R(t){T.call(this,{attributions:(t=t||{}).attributions,cacheSize:t.cacheSize,crossOrigin:t.crossOrigin,logo:t.logo,projection:t.projection,reprojectionErrorThreshold:t.reprojectionErrorThreshold,tileGrid:t.tileGrid,tileLoadFunction:t.tileLoadFunction,url:t.url,urls:t.urls,wrapX:void 0===t.wrapX||t.wrapX}),this.f=t.params||{},this.l=vt(),Lm(this,u1(this))}function u1(t){var e,o=0,i=[];for(e in t.f)i[o++]=e+"-"+t.f[e];return i.join("/")}function c1(t){jm.call(this,{opaque:!1,projection:t.projection,tileGrid:t.tileGrid,wrapX:void 0===t.wrapX||t.wrapX})}function f1(t,e,o){w0.call(this,t,2),this.c=e,this.Ia=o,this.a=null}function y1(t){var e;this.f=null,T.call(this,{attributions:t.attributions,cacheSize:t.cacheSize,crossOrigin:t.crossOrigin,projection:v("EPSG:3857"),reprojectionErrorThreshold:t.reprojectionErrorThreshold,state:"loading",tileLoadFunction:t.tileLoadFunction,wrapX:void 0===t.wrapX||t.wrapX}),t.url?t.jsonp?wm(t.url,this.og.bind(this),this.Ve.bind(this)):((e=new XMLHttpRequest).addEventListener("load",this.Ao.bind(this)),e.addEventListener("error",this.zo.bind(this)),e.open("GET",t.url),e.send()):t.tileJSON?this.og(t.tileJSON):O(!1,51)}function g1(t){var e;jm.call(this,{projection:v("EPSG:3857"),state:"loading"}),this.v=void 0===t.preemptive||t.preemptive,this.l=Pm,this.g=void 0,this.f=t.jsonp||!1,t.url?this.f?wm(t.url,this.pg.bind(this),this.We.bind(this)):((e=new XMLHttpRequest).addEventListener("load",this.Eo.bind(this)),e.addEventListener("error",this.Do.bind(this)),e.open("GET",t.url),e.send()):t.tileJSON?this.pg(t.tileJSON):O(!1,51)}function d1(t,e,o,i,r,n){w0.call(this,t,e),this.o=o,this.a=i,this.v=r,this.c=this.j=this.g=null,this.l=n}function v1(t){var e;0==t.state&&(t.state=1,t.l?wm(t.o,t.Ji.bind(t),t.De.bind(t)):((e=new XMLHttpRequest).addEventListener("load",t.Co.bind(t)),e.addEventListener("error",t.Bo.bind(t)),e.open("GET",t.o),e.send()))}function I(t){var e=(t=t||{}).params||{};T.call(this,{attributions:t.attributions,cacheSize:t.cacheSize,crossOrigin:t.crossOrigin,logo:t.logo,opaque:!(!("TRANSPARENT"in e)||e.TRANSPARENT),projection:t.projection,reprojectionErrorThreshold:t.reprojectionErrorThreshold,tileGrid:t.tileGrid,tileLoadFunction:t.tileLoadFunction,url:t.url,urls:t.urls,wrapX:void 0===t.wrapX||t.wrapX}),this.C=void 0!==t.gutter?t.gutter:0,this.f=e,this.l=!0,this.B=t.serverType,this.T=void 0===t.hidpi||t.hidpi,this.R="",m1(this),this.fa=vt(),x1(this),Lm(this,w1(this))}function b1(t,e,o,i,r,n,s){var a=t.urls;if(a){if(s.WIDTH=o[0],s.HEIGHT=o[1],s[t.l?"CRS":"SRS"]=n.mb,"STYLES"in t.f||(s.STYLES=""),1!=r)switch(t.B){case"geoserver":o=90*r+.5|0,s.FORMAT_OPTIONS="FORMAT_OPTIONS"in s?s.FORMAT_OPTIONS+";dpi:"+o:"dpi:"+o;break;case"mapserver":s.MAP_RESOLUTION=90*r;break;case"carmentaserver":case"qgis":s.DPI=90*r;break;default:O(!1,52)}return n=n.b,t.l&&"ne"==n.substr(0,2)&&(t=i[0],i[0]=i[1],i[1]=t,t=i[2],i[2]=i[3],i[3]=t),s.BBOX=i.join(","),Vm(1==a.length?a[0]:a[rt((e[1]<>=1,i>>=1;break;default:O(!1,53)}n.push([1,1]),n.reverse();for(var r=[1],s=[0],i=1,o=n.length;i=e+this.b&&a.height>=o+this.b)return s={offsetX:a.x+this.b,offsetY:a.y+this.b,image:this.f},this.c[t]=s,i.call(r,this.i,a.x+this.b,a.y+this.b),t=n,e+=this.b,i=o+this.b,e=a.width-e>a.height-i?(o={x:a.x+e,y:a.y,width:a.width-e,height:a.height},{x:a.x,y:a.y+i,width:e,height:a.height-i}):(o={x:a.x+e,y:a.y,width:a.width-e,height:i},{x:a.x,y:a.y+i,width:a.width,height:a.height-i}),F1(this,t,o,e),s}return null},k1.prototype.add=function(t,e,o,i,r,n){return!(e+this.b>this.i||o+this.b>this.i)&&(i=D1(this,!1,t,e,o,i,n))?(t=D1(this,!0,t,e,o,r||Y,n),{offsetX:i.offsetX,offsetY:i.offsetY,image:i.image,Zl:t.image}):null},t("ol.Attribution",Be),Be.prototype.getHTML=Be.prototype.i,t("ol.Collection",ho),ho.prototype.extend=ho.prototype.fg,ho.prototype.getArray=ho.prototype.tm,ho.prototype.getLength=ho.prototype.dc,ho.prototype.insertAt=ho.prototype.He,ho.prototype.removeAt=ho.prototype.Hg,ho.prototype.setAt=ho.prototype.Wp,t("ol.color.asArray",vo),t("ol.color.asString",bo),t("ol.colorlike.asColorLike",Mo),t("ol.control.defaults",Uo),t("ol.coordinate.add",er),t("ol.coordinate.createStringXY",function(e){return function(t){return ur(t,e)}}),t("ol.coordinate.format",rr),t("ol.coordinate.rotate",sr),t("ol.coordinate.toStringHDMS",function(t,e){return t?ir("NS",t[1],e)+" "+ir("EW",t[0],e):""}),t("ol.coordinate.toStringXY",ur),t("ol.DeviceOrientation",Uh),Uh.prototype.getAlpha=Uh.prototype.Fk,Uh.prototype.getBeta=Uh.prototype.Ik,Uh.prototype.getGamma=Uh.prototype.Ok,Uh.prototype.getHeading=Uh.prototype.um,Uh.prototype.getTracking=Uh.prototype.Th,Uh.prototype.setTracking=Uh.prototype.gg,t("ol.easing.easeIn",Ro),t("ol.easing.easeOut",Io),t("ol.easing.inAndOut",No),t("ol.easing.linear",Fo),t("ol.easing.upAndDown",function(t){return t<.5?No(2*t):1-No(2*(t-.5))}),t("ol.extent.boundingExtent",ht),t("ol.extent.buffer",lt),t("ol.extent.containsCoordinate",ft),t("ol.extent.containsExtent",yt),t("ol.extent.containsXY",gt),t("ol.extent.createEmpty",vt),t("ol.extent.equals",St),t("ol.extent.extend",Mt),t("ol.extent.getArea",Tt),t("ol.extent.getBottomLeft",jt),t("ol.extent.getBottomRight",Ct),t("ol.extent.getCenter",Lt),t("ol.extent.getHeight",It),t("ol.extent.getIntersection",Nt),t("ol.extent.getSize",function(t){return[t[2]-t[0],t[3]-t[1]]}),t("ol.extent.getTopLeft",Ft),t("ol.extent.getTopRight",kt),t("ol.extent.getWidth",Dt),t("ol.extent.intersects",Ot),t("ol.extent.isEmpty",Ut),t("ol.extent.applyTransform",Bt),t("ol.Feature",x),x.prototype.getGeometry=x.prototype.V,x.prototype.getId=x.prototype.wm,x.prototype.getGeometryName=x.prototype.Qk,x.prototype.getStyle=x.prototype.xm,x.prototype.getStyleFunction=x.prototype.Lc,x.prototype.setGeometry=x.prototype.Ra,x.prototype.setStyle=x.prototype.hg,x.prototype.setId=x.prototype.jc,x.prototype.setGeometryName=x.prototype.Tc,t("ol.featureloader.xhr",ml),t("ol.Geolocation",p0),p0.prototype.getAccuracy=p0.prototype.Dk,p0.prototype.getAccuracyGeometry=p0.prototype.Ek,p0.prototype.getAltitude=p0.prototype.Gk,p0.prototype.getAltitudeAccuracy=p0.prototype.Hk,p0.prototype.getHeading=p0.prototype.ym,p0.prototype.getPosition=p0.prototype.zm,p0.prototype.getProjection=p0.prototype.Uh,p0.prototype.getSpeed=p0.prototype.ll,p0.prototype.getTracking=p0.prototype.Vh,p0.prototype.getTrackingOptions=p0.prototype.Gh,p0.prototype.setProjection=p0.prototype.Wh,p0.prototype.setTracking=p0.prototype.Ke,p0.prototype.setTrackingOptions=p0.prototype.wj,t("ol.Graticule",c0),c0.prototype.getMap=c0.prototype.Cm,c0.prototype.getMeridians=c0.prototype.al,c0.prototype.getParallels=c0.prototype.hl,t("ol.has.DEVICE_PIXEL_RATIO",ni),t("ol.has.CANVAS",ai),t("ol.has.DEVICE_ORIENTATION",pi),t("ol.has.GEOLOCATION",hi),t("ol.has.TOUCH",li),t("ol.has.WEBGL",gi),b0.prototype.getImage=b0.prototype.Y,M0.prototype.getImage=M0.prototype.Y,t("ol.inherits",e),t("ol.interaction.defaults",hs),t("ol.Kinetic",sn),t("ol.loadingstrategy.all",Cv),t("ol.loadingstrategy.bbox",function(t){return[t]}),t("ol.loadingstrategy.tile",function(i){return function(t,e){e=i.tc(e),t=Ie(i,t,e);var o=[];for((e=[e,0,0])[1]=t.ca;e[1]<=t.$;++e[1])for(e[2]=t.da;e[2]<=t.ia;++e[2])o.push(i.Aa(e));return o}}),t("ol.Map",u),u.prototype.addControl=u.prototype.kk,u.prototype.addInteraction=u.prototype.lk,u.prototype.addLayer=u.prototype.ih,u.prototype.addOverlay=u.prototype.jh,u.prototype.forEachFeatureAtPixel=u.prototype.we,u.prototype.forEachLayerAtPixel=u.prototype.Im,u.prototype.hasFeatureAtPixel=u.prototype.Yl,u.prototype.getEventCoordinate=u.prototype.Tf,u.prototype.getEventPixel=u.prototype.xe,u.prototype.getTarget=u.prototype.ag,u.prototype.getTargetElement=u.prototype.jd,u.prototype.getCoordinateFromPixel=u.prototype.Wa,u.prototype.getControls=u.prototype.Lk,u.prototype.getOverlays=u.prototype.fl,u.prototype.getOverlayById=u.prototype.el,u.prototype.getInteractions=u.prototype.Sk,u.prototype.getLayerGroup=u.prototype.Kc,u.prototype.getLayers=u.prototype.Xh,u.prototype.getPixelFromCoordinate=u.prototype.Ja,u.prototype.getSize=u.prototype.Ob,u.prototype.getView=u.prototype.Z,u.prototype.getViewport=u.prototype.sl,u.prototype.renderSync=u.prototype.Tp,u.prototype.removeControl=u.prototype.Mp,u.prototype.removeInteraction=u.prototype.Np,u.prototype.removeLayer=u.prototype.Pp,u.prototype.removeOverlay=u.prototype.Qp,u.prototype.setLayerGroup=u.prototype.qj,u.prototype.setSize=u.prototype.Qg,u.prototype.setTarget=u.prototype.Le,u.prototype.setView=u.prototype.iq,u.prototype.updateSize=u.prototype.Ad,t("ol.Object",ro),ro.prototype.getKeys=ro.prototype.O,ro.prototype.getProperties=ro.prototype.N,ro.prototype.setProperties=ro.prototype.H,ro.prototype.unset=ro.prototype.P,t("ol.Observable",io),t("ol.Observable.unByKey",function(t){if(Array.isArray(t))for(var e=0,o=t.length;eb?1:ac)for(c=1;c>>0,d,e=0;e=b.ca&&a.da<=b.ia&&a.ia>=b.da};function Ca(a,b,c){return Math.min(Math.max(a,b),c)}var Da=function(){var a;"cosh"in Math?a=Math.cosh:a=function(a){a=Math.exp(a);return(a+1/a)/2};return a}();function Ea(a){xa(0a*b?a+b:a} +function Ja(a,b,c){return a+c*(b-a)};function Ka(a,b,c){void 0===c&&(c=[0,0]);c[0]=a[0]+2*b;c[1]=a[1]+2*b;return c}function La(a,b,c){void 0===c&&(c=[0,0]);c[0]=a[0]*b+.5|0;c[1]=a[1]*b+.5|0;return c}function Ma(a,b){if(Array.isArray(a))return a;void 0===b?b=[a,a]:b[0]=b[1]=a;return b};function Na(a){for(var b=Oa(),c=0,d=a.length;cd&&(g|=4);be&&(g|=2);g||(g=1);return g}function Oa(){return[Infinity,Infinity,-Infinity,-Infinity]}function Xa(a,b,c,d,e){return e?(e[0]=a,e[1]=b,e[2]=c,e[3]=d,e):[a,b,c,d]}function Ya(a){return Xa(Infinity,Infinity,-Infinity,-Infinity,a)}function Za(a,b){var c=a[0];a=a[1];return Xa(c,a,c,a,b)}function $a(a,b,c,d,e){e=Ya(e);return ab(e,a,b,c,d)} +function bb(a,b){return a[0]==b[0]&&a[2]==b[2]&&a[1]==b[1]&&a[3]==b[3]}function cb(a,b){b[0]a[2]&&(a[2]=b[2]);b[1]a[3]&&(a[3]=b[3]);return a}function Pa(a,b){b[0]a[2]&&(a[2]=b[0]);b[1]a[3]&&(a[3]=b[1])}function ab(a,b,c,d,e){for(;cb[0]?a[0]:b[0],c[1]=a[1]>b[1]?a[1]:b[1],c[2]=a[2]=b[0]&&a[1]<=b[3]&&a[3]>=b[1]}function kb(a){return a[2]Fb?f=Fb:f<-Fb&&(f=-Fb);b[e+1]=f}return b}function Ib(a,b,c){var d=a.length;c=1>=1}return c.join("")};function lc(a){this.minZoom=void 0!==a.minZoom?a.minZoom:0;this.b=a.resolutions;xa(ta(this.b,function(a,b){return b-a}),17);this.maxZoom=this.b.length-1;this.i=void 0!==a.origin?a.origin:null;this.c=null;void 0!==a.origins&&(this.c=a.origins,xa(this.c.length==this.b.length,20));var b=a.extent;void 0===b||this.i||this.c||(this.i=ib(b));xa(!this.i&&this.c||this.i&&!this.c,18);this.f=null;void 0!==a.tileSizes&&(this.f=a.tileSizes,xa(this.f.length==this.b.length,19));this.g=void 0!==a.tileSize?a.tileSize: +this.f?null:256;xa(!this.g&&this.f||this.g&&!this.f,22);this.v=void 0!==b?b:null;this.a=null;this.j=[0,0];void 0!==a.sizes?this.a=a.sizes.map(function(a){return new ya(Math.min(0,a[0]),Math.max(a[0]-1,-1),Math.min(0,a[1]),Math.max(a[1]-1,-1))},this):b&&mc(this,b)}var nc=[0,0,0];k=lc.prototype;k.Rf=function(a,b,c){a=oc(this,a,b);for(var d=a.ca,e=a.$;d<=e;++d)for(var f=a.da,g=a.ia;f<=g;++f)c([b,d,f])}; +function pc(a,b,c,d,e){e=a.Aa(b,e);for(b=b[0]-1;b>=a.minZoom;){if(c.call(null,b,oc(a,e,b,d)))return!0;--b}return!1}k.G=function(){return this.v};k.Ti=function(){return this.maxZoom};k.Ui=function(){return this.minZoom};k.Pc=function(a){return this.i?this.i:this.c[a]};k.Da=function(a){return this.b[a]};k.Vi=function(){return this.b};function qc(a,b,c,d){return b[0]M.$)if(Ba(z,new ya(Ia(B.ca,ba),Ia(B.$,ba),B.da,B.ia))||B.$-B.ca+1>ba&&Ba(z,M)){E=!0;break a}}}E=!1}else E=!0}}else E=!1;E?(x in l&&delete l[x],E=u.b,E in m||(m[E]=!0,h[x]=u)):l[x]=u}}}}b=[h,l];p=b[0];b=b[1];for(var da in this.l)da in p?(this.j[da]||(this.l[da].style.display="",this.j[da]=!0),delete p[da]):da in b?(this.j[da]&&(this.l[da].style.display="none",delete this.j[da]),delete b[da]):(ld(this.l[da]),delete this.l[da],delete this.j[da]);for(da in p)r= +document.createElement("LI"),r.innerHTML=p[da].b,this.I.appendChild(r),this.l[da]=r,this.j[da]=!0;for(da in b)r=document.createElement("LI"),r.innerHTML=b[da].b,r.style.display="none",this.I.appendChild(r),this.l[da]=r;da=!wb(this.j)||!wb(a.logos);this.B!=da&&(this.element.style.display=da?"":"none",this.B=da);da&&wb(this.j)?this.element.classList.add("ol-logo-only"):this.element.classList.remove("ol-logo-only");a=a.logos;da=this.T;for(ca in da)ca in a||(ld(da[ca]),delete da[ca]);for(var fb in a)if(b= +a[fb],b instanceof HTMLElement&&(this.u.appendChild(b),da[fb]=b),!(fb in da)){var ca=new Image;ca.src=fb;""===b?p=ca:(p=document.createElement("a"),p.href=b,p.appendChild(ca));this.u.appendChild(p);da[fb]=p}this.u.style.display=wb(a)?"none":""}else this.B&&(this.element.style.display="none",this.B=!1)}k=nd.prototype;k.Vm=function(a){a.preventDefault();pd(this)};function pd(a){a.element.classList.toggle("ol-collapsed");a.c?kd(a.D,a.C):kd(a.C,a.D);a.c=!a.c}k.Um=function(){return this.o}; +k.Xm=function(a){this.o!==a&&(this.o=a,this.element.classList.toggle("ol-uncollapsible"),!a&&this.c&&pd(this))};k.Wm=function(a){this.o&&this.c!==a&&pd(this)};k.Tm=function(){return this.c};function qd(a){return Math.pow(a,3)}function rd(a){return 1-qd(1-a)}function sd(a){return 3*a*a-2*a*a*a}function td(a){return a};function ud(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-rotate",c=void 0!==a.label?a.label:"\u21e7";this.c=null;"string"===typeof c?(this.c=document.createElement("span"),this.c.className="ol-compass",this.c.textContent=c):(this.c=c,this.c.classList.add("ol-compass"));var d=a.tipLabel?a.tipLabel:"Reset rotation",c=document.createElement("button");c.className=b+"-reset";c.setAttribute("type","button");c.title=d;c.appendChild(this.c);y(c,"click",ud.prototype.D,this);d=document.createElement("div"); +d.className=b+" ol-unselectable ol-control";d.appendChild(c);b=a.render?a.render:vd;this.o=a.resetNorth?a.resetNorth:void 0;md.call(this,{element:d,render:b,target:a.target});this.l=void 0!==a.duration?a.duration:250;this.j=void 0!==a.autoHide?a.autoHide:!0;this.u=void 0;this.j&&this.element.classList.add("ol-hidden")}v(ud,md);ud.prototype.D=function(a){a.preventDefault();this.o?this.o():(a=this.a.Z())&&void 0!==a.Qa()&&(0=Math.abs(c-f[0])&&25>=g)return!0}return!1}function ie(a){var b=je(a,a),c=b.preventDefault;b.preventDefault=function(){a.preventDefault();c()};b.pointerId=1;b.isPrimary=!0;b.pointerType="mouse";return b}k=ge.prototype; +k.fm=function(a){if(!he(this,a)){(1).toString()in this.a&&this.cancel(a);var b=ie(a);this.a[(1).toString()]=a;ke(this.b,"pointerdown",b,a)}};k.gm=function(a){if(!he(this,a)){var b=ie(a);ke(this.b,"pointermove",b,a)}};k.jm=function(a){if(!he(this,a)){var b=this.a[(1).toString()];b&&b.button===a.button&&(b=ie(a),ke(this.b,"pointerup",b,a),delete this.a[(1).toString()])}};k.im=function(a){if(!he(this,a)){var b=ie(a);le(this.b,b,a)}};k.hm=function(a){if(!he(this,a)){var b=ie(a);me(this.b,b,a)}}; +k.cancel=function(a){var b=ie(a);this.b.cancel(b,a);delete this.a[(1).toString()]};function ne(a){fe.call(this,a,{MSPointerDown:this.om,MSPointerMove:this.pm,MSPointerUp:this.sm,MSPointerOut:this.qm,MSPointerOver:this.rm,MSPointerCancel:this.nm,MSGotPointerCapture:this.lm,MSLostPointerCapture:this.mm});this.a=a.i;this.i=["","unavailable","touch","pen","mouse"]}v(ne,fe);function oe(a,b){var c=b;"number"===typeof b.pointerType&&(c=je(b,b),c.pointerType=a.i[b.pointerType]);return c}k=ne.prototype; +k.om=function(a){this.a[a.pointerId.toString()]=a;var b=oe(this,a);ke(this.b,"pointerdown",b,a)};k.pm=function(a){var b=oe(this,a);ke(this.b,"pointermove",b,a)};k.sm=function(a){var b=oe(this,a);ke(this.b,"pointerup",b,a);delete this.a[a.pointerId.toString()]};k.qm=function(a){var b=oe(this,a);me(this.b,b,a)};k.rm=function(a){var b=oe(this,a);le(this.b,b,a)};k.nm=function(a){var b=oe(this,a);this.b.cancel(b,a);delete this.a[a.pointerId.toString()]}; +k.mm=function(a){this.b.b(new pe("lostpointercapture",a,a))};k.lm=function(a){this.b.b(new pe("gotpointercapture",a,a))};function qe(a){fe.call(this,a,{pointerdown:this.ip,pointermove:this.jp,pointerup:this.mp,pointerout:this.kp,pointerover:this.lp,pointercancel:this.hp,gotpointercapture:this.ul,lostpointercapture:this.em})}v(qe,fe);k=qe.prototype;k.ip=function(a){re(this.b,a)};k.jp=function(a){re(this.b,a)};k.mp=function(a){re(this.b,a)};k.kp=function(a){re(this.b,a)};k.lp=function(a){re(this.b,a)};k.hp=function(a){re(this.b,a)};k.em=function(a){re(this.b,a)};k.ul=function(a){re(this.b,a)};function pe(a,b,c){Oc.call(this,a);this.b=b;a=c?c:{};this.buttons=se(a);this.pressure=te(a,this.buttons);this.bubbles="bubbles"in a?a.bubbles:!1;this.cancelable="cancelable"in a?a.cancelable:!1;this.view="view"in a?a.view:null;this.detail="detail"in a?a.detail:null;this.screenX="screenX"in a?a.screenX:0;this.screenY="screenY"in a?a.screenY:0;this.clientX="clientX"in a?a.clientX:0;this.clientY="clientY"in a?a.clientY:0;this.ctrlKey="ctrlKey"in a?a.ctrlKey:!1;this.altKey="altKey"in a?a.altKey:!1;this.shiftKey= +"shiftKey"in a?a.shiftKey:!1;this.metaKey="metaKey"in a?a.metaKey:!1;this.button="button"in a?a.button:0;this.relatedTarget="relatedTarget"in a?a.relatedTarget:null;this.pointerId="pointerId"in a?a.pointerId:0;this.width="width"in a?a.width:0;this.height="height"in a?a.height:0;this.tiltX="tiltX"in a?a.tiltX:0;this.tiltY="tiltY"in a?a.tiltY:0;this.pointerType="pointerType"in a?a.pointerType:"";this.isPrimary="isPrimary"in a?a.isPrimary:!1;b.preventDefault&&(this.preventDefault=function(){b.preventDefault()})} +v(pe,Oc);function se(a){if(a.buttons||ue)a=a.buttons;else switch(a.which){case 1:a=1;break;case 2:a=4;break;case 3:a=2;break;default:a=0}return a}function te(a,b){var c=0;a.pressure?c=a.pressure:c=b?.5:0;return c}var ue=!1;try{ue=1===(new MouseEvent("click",{buttons:1})).buttons}catch(a){};function ve(a,b){fe.call(this,a,{touchstart:this.rq,touchmove:this.qq,touchend:this.pq,touchcancel:this.oq});this.a=a.i;this.j=b;this.i=void 0;this.g=0;this.c=void 0}v(ve,fe);k=ve.prototype;k.ij=function(){this.g=0;this.c=void 0}; +function we(a,b,c){b=je(b,c);b.pointerId=c.identifier+2;b.bubbles=!0;b.cancelable=!0;b.detail=a.g;b.button=0;b.buttons=1;b.width=c.webkitRadiusX||c.radiusX||0;b.height=c.webkitRadiusY||c.radiusY||0;b.pressure=c.webkitForce||c.force||.5;b.isPrimary=a.i===c.identifier;b.pointerType="touch";b.clientX=c.clientX;b.clientY=c.clientY;b.screenX=c.screenX;b.screenY=c.screenY;return b} +function xe(a,b,c){function d(){b.preventDefault()}var e=Array.prototype.slice.call(b.changedTouches),f=e.length,g;for(g=0;g=b.length){var e=[],f;for(f=0;fa.D||Math.abs(b.clientY-a.c.clientY)>a.D}k.ka=function(){this.v&&(Ec(this.v),this.v=null);this.l&&(Ec(this.l),this.l=null);this.f.forEach(Ec);this.f.length=0;this.a&&(Nc(this.a),this.a=null);this.g&&(Nc(this.g),this.g=null);Qc.prototype.ka.call(this)};function Ke(a,b){this.l=a;this.c=b;this.b=[];this.i=[];this.a={}}Ke.prototype.clear=function(){this.b.length=0;this.i.length=0;ub(this.a)};function Le(a){var b=a.b,c=a.i,d=b[0];1==b.length?(b.length=0,c.length=0):(b[0]=b.pop(),c[0]=c.pop(),Me(a,0));b=a.c(d);delete a.a[b];return d}Ke.prototype.f=function(a){xa(!(this.c(a)in this.a),31);var b=this.l(a);return Infinity!=b?(this.b.push(a),this.i.push(b),this.a[this.c(a)]=!0,Ne(this,0,this.b.length-1),!0):!1}; +function Me(a,b){for(var c=a.b,d=a.i,e=c.length,f=c[b],g=d[b],h=b;b>1;){var l=2*b+1,m=2*b+2,l=mb;){var g=c-1>>1;if(a[g]>f)d[c]=d[g],a[c]=a[g],c=g;else break}d[c]=e;a[c]=f} +function Oe(a){var b=a.l,c=a.b,d=a.i,e=0,f=c.length,g;for(g=0;g>1)-1;0<=b;b--)Me(a,b)};function Pe(a,b){Ke.call(this,function(b){return a.apply(null,b)},function(a){return a[0].bb()});this.v=b;this.j=0;this.g={}}v(Pe,Ke);Pe.prototype.f=function(a){var b=Ke.prototype.f.call(this,a);b&&y(a[0],"change",this.o,this);return b};Pe.prototype.o=function(a){a=a.target;var b=a.getState();if(2===b||3===b||4===b||5===b)Kc(a,"change",this.o,this),a=a.bb(),a in this.g&&(delete this.g[a],--this.j),this.v()}; +function Qe(a,b,c){for(var d=0,e,f;a.je)return 1;if(e>d)return-1}return 0};function Ze(a,b){a[0]+=b[0];a[1]+=b[1];return a}function $e(a,b){var c=b.pd(),d=b.wa();b=d[0];var d=d[1],e=a[0]-b;a=a[1]-d;e||a||(e=1);var f=Math.sqrt(e*e+a*a);return[b+c*e/f,d+c*a/f]}function af(a,b){var c=a[0];a=a[1];var d=b[0],e=b[1];b=d[0];var d=d[1],f=e[0],e=e[1],g=f-b,h=e-d,c=g||h?(g*(c-b)+h*(a-d))/(g*g+h*h||0):0;0>=c?(a=b,c=d):1<=c?(a=f,c=e):(a=b+c*g,c=d+c*h);return[a,c]} +function bf(a,b,c){b=Ia(b+180,360)-180;var d=Math.abs(3600*b);c=c||0;var e=Math.pow(10,c),f=Math.floor(d/3600),g=Math.floor((d-3600*f)/60),d=Math.ceil((d-3600*f-60*g)*e)/e;60<=d&&(d=0,g+=1);60<=g&&(g=0,f+=1);return f+"\u00b0 "+Xe(g)+"\u2032 "+Xe(d,c)+"\u2033"+(b?" "+a.charAt(0>b?1:0):"")}function cf(a,b,c){return a?b.replace("{x}",a[0].toFixed(c)).replace("{y}",a[1].toFixed(c)):""}function df(a,b){for(var c=!0,d=a.length-1;0<=d;--d)if(a[d]!=b[d]){c=!1;break}return c} +function ef(a,b){var c=Math.cos(b);b=Math.sin(b);var d=a[1]*c+a[0]*b;a[0]=a[0]*c-a[1]*b;a[1]=d;return a}function gf(a,b){a[0]*=b;a[1]*=b}function hf(a,b){var c=a[0]-b[0];a=a[1]-b[1];return c*c+a*a}function jf(a,b){return Math.sqrt(hf(a,b))}function kf(a,b){return hf(a,af(a,b))}function lf(a,b){return cf(a,"{x}, {y}",b)};function mf(){return!0}function nf(){return!1};function of(){Tc.call(this);this.l=Oa();this.v=-1;this.f={};this.o=this.g=0}v(of,Tc);k=of.prototype;k.Ab=function(a,b){b=b?b:[NaN,NaN];this.Kb(a[0],a[1],b,Infinity);return b};k.sb=function(a){return this.Mc(a[0],a[1])};k.Mc=nf;k.G=function(a){this.v!=this.i&&(this.l=this.se(this.l),this.v=this.i);var b=this.l;a?(a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3]):a=b;return a};k.Rb=function(a){return this.Vd(a*a)};k.tb=function(a,b){this.Dc(ec(a,b));return this};function pf(a,b,c,d,e,f){for(var g=f?f:[],h=0;ba||this.g&&a<=this.g)return this;var b=a.toString();if(this.f.hasOwnProperty(b))return this.f[b];var c=this.hd(a);if(c.ga().lengthe&&(e=f);f=h;g=l}return e}function zf(a,b,c,d,e){var f;var g=0;for(f=c.length;gh){for(;br&&(m=n,r=A)}r>e&&(l[(m-b)/d]=1,q+dga&&Mga)&&(0>z&&baz)||(x[B++]=L,x[B++]=g,E=L,A=g);L=oa;g=ha}}x[B++]=L;x[B++]=g}g=B}h.push(g);b=n}return g};function Jf(a,b){rf.call(this);this.c=this.j=-1;this.ma(a,b)}v(Jf,rf);k=Jf.prototype;k.clone=function(){var a=new Jf(null);Kf(a,this.ja,this.A.slice());return a};k.Kb=function(a,b,c,d){if(df&&0<(m-h)*(f-l)-(e-h)*(n-l)&&g++:n<=f&&0>(m-h)*(f-l)-(e-h)*(n-l)&&g--;h=m;l=n}return!!g}function Nf(a,b,c,d,e,f){if(!c.length||!Mf(a,b,c[0],d,e,f))return!1;var g;b=1;for(g=c.length;bq&&(p=(p+r)/2,Nf(a,b,c,d,p,l)&&(n=p,q=x));p=r}isNaN(n)&&(n=e[f]);return g?(g.push(n,l),g):[n,l]};function Pf(a,b,c,d,e,f){for(var g=[a[b],a[b+1]],h=[],l;b+d=e[0]&&f[2]<=e[2]||f[1]>=e[1]&&f[3]<=e[3]?!0:Pf(a,b,c,d,function(a,b){var c=!1,d=Wa(e,a),f=Wa(e,b);if(1===d||1===f)c=!0;else{var g=e[0],h=e[1],r=e[2],u=e[3],x=b[0];b=b[1];a=(b-a[1])/(x-a[0]);f&2&&!(d&2)&&(c=x-(b-u)/a,c=c>=g&&c<=r);c||!(f&4)||d&4||(c=b-(x-r)*a,c=c>=h&&c<=u);c||!(f&8)||d&8||(c=x-(b-h)/a,c=c>=g&&c<=r);c||!(f&16)||d&16||(c=b-(x-g)*a,c=c>=h&&c<=u)}return c}):!1} +function Rf(a,b,c,d,e){var f=c[0];if(!(Qf(a,b,f,d,e)||Mf(a,b,f,d,e[0],e[1])||Mf(a,b,f,d,e[0],e[3])||Mf(a,b,f,d,e[2],e[1])||Mf(a,b,f,d,e[2],e[3])))return!1;if(1===c.length)return!0;b=1;for(f=c.length;ba||this.c.length<=a)return null;var b=new Jf(null);Kf(b,this.ja,this.A.slice(a?this.c[a-1]:0,this.c[a]));return b};k.Sd=function(){var a=this.ja,b=this.A,c=this.c,d=[],e=0,f;var g=0;for(f=c.length;g=this.f&&a<=this.a){var b=this.l||0;if(this.j){var c=ka(this.j,a,1);b+=c;if(c==this.j.length-1)return b;var d=this.j[c];c=d/this.j[c+1]}else d=this.a,c=this.C;b+=Math.log(d/a)/Math.log(c)}return b}; +k.Qf=function(a,b){b=b||{};var c=b.size;c||(c=gg(this));if(a instanceof rf)if("Circle"===a.U()){a=a.G();var d=Yf(a);d.rotate(this.Qa(),nb(a))}else d=a;else xa(Array.isArray(a),24),xa(!kb(a),25),d=Yf(a);var e=b.padding?b.padding:[0,0,0,0],f=void 0!==b.constrainResolution?b.constrainResolution:!0,g=void 0!==b.nearest?b.nearest:!1,h;void 0!==b.minResolution?h=b.minResolution:void 0!==b.maxZoom?h=this.constrainResolution(this.a,b.maxZoom-this.l,0):h=0;var l=d.ga(),m=this.Qa();a=Math.cos(-m);var m=Math.sin(-m), +n=Infinity,p=Infinity,q=-Infinity,r=-Infinity;d=d.qa();for(var u=0,x=l.length;ua.b.length)return!1;var b=Date.now()-a.g,c=a.b.length-3;if(a.b[c+2]b;)d-=3;b=a.b[c+2]-a.b[d+2];if(b<1E3/60)return!1;var e=a.b[c]-a.b[d],c=a.b[c+1]-a.b[d+1];a.i=Math.atan2(c,e);a.a=Math.sqrt(e*e+c*c)/b;return a.a>a.c};function ng(a){Tc.call(this);this.v=null;this.Ha(!0);this.handleEvent=a.handleEvent}v(ng,Tc);ng.prototype.c=function(){return this.get("active")};ng.prototype.f=function(){return this.v};ng.prototype.Ha=function(a){this.set("active",a)};ng.prototype.setMap=function(a){this.v=a};function og(a,b,c,d){if(void 0!==b){var e=a.Qa(),f=a.wa();void 0!==e&&f&&0=this.u}function Tg(a){if(Bg(a)){var b=this.a,c=a.pixel;b.c=this.g;b.i=c;Qg(b);Pg(b);this.b(new Wg(Xg,a.coordinate,a))}}Rg.prototype.V=function(){return this.a.V()}; +Rg.prototype.j=ua;function Ug(a){if(!Bg(a))return!0;this.a.setMap(null);this.l(a,this.g,a.pixel)&&(this.j(a),this.b(new Wg(Yg,a.coordinate,a)));return!1}function Sg(a){if(Bg(a)&&ug(a)&&this.C(a)){this.g=a.pixel;this.a.setMap(a.map);var b=this.a,c=this.g;b.c=this.g;b.i=c;Qg(b);Pg(b);this.b(new Wg(Zg,a.coordinate,a));return!0}return!1}var Zg="boxstart",Xg="boxdrag",Yg="boxend";function Wg(a,b,c){Oc.call(this,a);this.coordinate=b;this.mapBrowserEvent=c}v(Wg,Oc);function $g(a){a=a?a:{};var b=a.condition?a.condition:yg;this.B=void 0!==a.duration?a.duration:200;this.I=void 0!==a.out?a.out:!1;Rg.call(this,{condition:b,className:a.className||"ol-dragzoom"})}v($g,Rg); +$g.prototype.j=function(){var a=this.v,b=a.Z(),c=a.Ob(),d=this.V().G();if(this.I){var e=b.dd(c),d=[a.Ja(eb(d)),a.Ja(hb(d))],a=Ya(void 0),f;var g=0;for(f=d.length;gMath.abs(d)?gh:hh;if(this.o===gh){b=b.Z();this.l?clearTimeout(this.l): +cg(b,1,1);this.l=setTimeout(this.B.bind(this),400);var c=b.Pa()*Math.pow(2,d/300),e=b.f,f=b.a,g=0;cf&&(c=Math.min(c,1.5*f),g=-1);if(this.a){var h=eg(b,c,this.a);b.ob(b.Ec(h))}b.Vc(c);!g&&this.R&&b.animate({resolution:b.constrainResolution(c,0g&&b.animate({resolution:f,easing:rd,anchor:this.a,duration:500});this.g=a;return!1}this.j+=d;d=Math.max(this.na- +(a-this.g),0);clearTimeout(this.u);this.u=setTimeout(this.I.bind(this,b),d);return!1}eh.prototype.B=function(){this.l=void 0;cg(this.v.Z(),1,-1)};eh.prototype.I=function(a){a=a.Z();a.Ic()&&a.ed();pg(a,-Ca(this.j,-1,1),this.a,this.D);this.o=void 0;this.j=0;this.a=null;this.u=this.g=void 0};eh.prototype.T=function(a){this.C=a;a||(this.a=null)};var gh="trackpad",hh="wheel";function ih(a){Dg.call(this,{handleDownEvent:jh,handleDragEvent:kh,handleUpEvent:lh});a=a||{};this.g=null;this.j=void 0;this.a=!1;this.l=0;this.C=void 0!==a.threshold?a.threshold:.3;this.u=void 0!==a.duration?a.duration:250}v(ih,Dg); +function kh(a){var b=0,c=this.o[0],d=this.o[1],c=Math.atan2(d.clientY-c.clientY,d.clientX-c.clientX);void 0!==this.j&&(b=c-this.j,this.l+=b,!this.a&&Math.abs(this.l)>this.C&&(this.a=!0));this.j=c;a=a.map;c=a.Z();if(c.g.rotation!==Te){var d=a.a.getBoundingClientRect(),e=Fg(this.o);e[0]-=d.left;e[1]-=d.top;this.g=a.Wa(e);this.a&&(d=c.Qa(),a.render(),og(c,d+b,this.g))}} +function lh(a){if(2>this.o.length){a=a.map.Z();cg(a,1,-1);if(this.a){var b=a.Qa(),c=this.g,d=this.u,b=a.constrainRotation(b,0);og(a,b,c,d)}return!1}return!0}function jh(a){return 2<=this.o.length?(a=a.map,this.g=null,this.j=void 0,this.a=!1,this.l=0,this.D||cg(a.Z(),1,1),!0):!1}ih.prototype.Xc=nf;function mh(a){Dg.call(this,{handleDownEvent:nh,handleDragEvent:oh,handleUpEvent:ph});a=a?a:{};this.l=a.constrainResolution||!1;this.g=null;this.u=void 0!==a.duration?a.duration:400;this.a=void 0;this.j=1}v(mh,Dg); +function oh(a){var b=1,c=this.o[0],d=this.o[1],e=c.clientX-d.clientX,c=c.clientY-d.clientY,e=Math.sqrt(e*e+c*c);void 0!==this.a&&(b=this.a/e);this.a=e;a=a.map;var e=a.Z(),d=e.Pa(),f=e.a,g=e.f,c=d*b;c>f?(b=f/d,c=f):cthis.o.length){a=a.map.Z();cg(a,1,-1);var b=a.Pa();if(this.l||ba.a){var c=this.g,d=this.u,b=a.constrainResolution(b,0,this.j-1);qg(a,b,c,d)}return!1}return!0}function nh(a){return 2<=this.o.length?(a=a.map,this.g=null,this.a=void 0,this.j=1,this.D||cg(a.Z(),1,1),!0):!1}mh.prototype.Xc=nf;function qh(a){a=a?a:{};var b=new Yc,c=new kg(-.005,.05,100);(void 0!==a.altShiftDragRotate?a.altShiftDragRotate:1)&&b.push(new Kg);(void 0!==a.doubleClickZoom?a.doubleClickZoom:1)&&b.push(new rg({delta:a.zoomDelta,duration:a.zoomDuration}));(void 0!==a.dragPan?a.dragPan:1)&&b.push(new Gg({kinetic:c}));(void 0!==a.pinchRotate?a.pinchRotate:1)&&b.push(new ih);(void 0!==a.pinchZoom?a.pinchZoom:1)&&b.push(new mh({constrainResolution:a.constrainResolution,duration:a.zoomDuration}));if(void 0!==a.keyboard? +a.keyboard:1)b.push(new ah),b.push(new ch({delta:a.zoomDelta,duration:a.zoomDuration}));(void 0!==a.mouseWheelZoom?a.mouseWheelZoom:1)&&b.push(new eh({constrainResolution:a.constrainResolution,duration:a.zoomDuration}));(void 0!==a.shiftDragZoom?a.shiftDragZoom:1)&&b.push(new $g({duration:a.zoomDuration}));return b};function sh(a){Tc.call(this);var b=tb({},a);b.opacity=void 0!==a.opacity?a.opacity:1;b.visible=void 0!==a.visible?a.visible:!0;b.zIndex=void 0!==a.zIndex?a.zIndex:0;b.maxResolution=void 0!==a.maxResolution?a.maxResolution:Infinity;b.minResolution=void 0!==a.minResolution?a.minResolution:0;this.H(b);this.a={layer:this,Je:!0}}v(sh,Tc); +function th(a){a.a.opacity=Ca(a.hc(),0,1);a.a.yj=a.$f();a.a.visible=a.Mb();a.a.extent=a.G();a.a.zIndex=a.Ba();a.a.maxResolution=a.fc();a.a.minResolution=Math.max(a.gc(),0);return a.a}k=sh.prototype;k.G=function(){return this.get("extent")};k.fc=function(){return this.get("maxResolution")};k.gc=function(){return this.get("minResolution")};k.hc=function(){return this.get("opacity")};k.Mb=function(){return this.get("visible")};k.Ba=function(){return this.get("zIndex")}; +k.vc=function(a){this.set("extent",a)};k.Ac=function(a){this.set("maxResolution",a)};k.Bc=function(a){this.set("minResolution",a)};k.wc=function(a){this.set("opacity",a)};k.xc=function(a){this.set("visible",a)};k.Vb=function(a){this.set("zIndex",a)};function uh(a){var b=a||{};a=tb({},b);delete a.layers;b=b.layers;sh.call(this,a);this.f=[];this.c={};y(this,Vc(vh),this.Hl,this);b?Array.isArray(b)?b=new Yc(b.slice(),{unique:!0}):xa(b instanceof Yc,43):b=new Yc(void 0,{unique:!0});this.xi(b)}v(uh,sh);k=uh.prototype;k.Fd=function(){};k.Fe=function(){this.Mb()&&this.s()}; +k.Hl=function(){this.f.forEach(Ec);this.f.length=0;var a=this.qd();this.f.push(y(a,"add",this.Gl,this),y(a,"remove",this.Il,this));for(var b in this.c)this.c[b].forEach(Ec);ub(this.c);var a=a.a,c;b=0;for(c=a.length;b=a.minResolution&&bp[2])m=[r+q*Math.ceil((p[0]-r)/q),a[1]]}p=b.layerStatesArray;for(q=p.length-1;0<=q;--q){var u=p[q],r=u.layer;if(xh(u,n)&&f.call(g,r)&&(u=Ph(this,r),r.ha()&&(l=u.Ea(r.ha().u?m:a,b,c,h,e)),l))return l}}; +k.Ei=function(a,b,c,d,e){return void 0!==this.Ea(a,b,c,mf,this,d,e)};function Ph(a,b){var c=w(b).toString();if(c in a.c)return a.c[c];b=b.Fd(a);a.c[c]=b;a.v[c]=y(b,"change",a.Fl,a);return b}k.Fl=function(){this.o.render()};k.Jg=ua;k.Rp=function(a,b){for(var c in this.c)if(!(b&&c in b.layerStates)){a=c;var d=this.c[a];delete this.c[a];Ec(this.v[a]);delete this.v[a];Nc(d)}};function Qh(a,b){for(var c in a.c)if(!(c in b.layerStates)){b.postRenderFunctions.push(a.Rp.bind(a));break}} +function ra(a,b){return a.zIndex-b.zIndex};function Rh(a,b,c,d,e){Oc.call(this,a);this.vectorContext=b;this.frameState=c;this.context=d;this.glContext=e}v(Rh,Oc);var Sh=[0,0,0,1],Th=[],Uh=[0,0,0,1];function Vh(a,b,c,d){b&&(a.translate(c,d),a.rotate(b),a.translate(-c,-d))};function Wh(){}k=Wh.prototype;k.zb=function(){};k.rd=function(){};k.Zb=function(){};k.te=function(){};k.ue=function(){};k.mc=function(){};k.nc=function(){};k.oc=function(){};k.pc=function(){};k.qc=function(){};k.rc=function(){};k.yc=function(){};k.Ma=function(){};k.Ub=function(){};k.Cb=function(){};function Xh(a,b,c,d,e){this.i=a;this.u=b;this.c=c;this.S=d;this.Yb=e;this.M=this.b=this.a=this.Ua=this.R=this.I=null;this.na=this.T=this.l=this.B=this.C=this.D=0;this.fa=!1;this.f=this.fb=0;this.pa=!1;this.oa=0;this.Ia="";this.va=this.Jb=0;this.Sa=!1;this.j=this.$a=0;this.ra=this.o=this.g=null;this.v=[];this.xb=Bh()}v(Xh,Wh); +function Yh(a,b,c){if(a.M){b=pf(b,0,c,2,a.S,a.v);c=a.i;var d=a.xb,e=c.globalAlpha;1!=a.l&&(c.globalAlpha=e*a.l);var f=a.fb;a.fa&&(f+=a.Yb);var g;var h=0;for(g=b.length;h=-Ci?void 0:0f;f+=d)this.a[b++]=a[f],this.a[b++]=a[f+1],this.a[b++]=0,this.a[b++]=this.S,this.a[b++]=a[f],this.a[b++]=a[f+1],this.a[b++]=1,this.a[b++]=this.S,this.a[b++]=a[f],this.a[b++]=a[f+1],this.a[b++]=2,this.a[b++]=this.S,this.a[b++]=a[f],this.a[b++]= +a[f+1],this.a[b++]=3,this.a[b++]=this.S,this.b[c++]=e,this.b[c++]=e+1,this.b[c++]=e+2,this.b[c++]=e+2,this.b[c++]=e+3,this.b[c++]=e,e+=4}else this.c.s&&(this.j.pop(),this.j.length&&(d=this.j[this.j.length-1],this.c.fillColor=d[0],this.c.strokeColor=d[1],this.c.lineWidth=d[2],this.c.s=!1))};k.Db=function(){this.l=new Di(this.a);this.o=new Di(this.b);this.i.push(this.b.length);!this.u.length&&0=h;){var l=this.i[g];var m=this.f[g];m=w(m).toString();c[m]&&(d!==f&&xi(a,b,d,f),f=l);g--;d=l}d!==f&&xi(a,b,d,f);d=f=h}}}; +k.ve=function(a,b,c,d,e){var f,g;var h=this.i.length-2;var l=this.i[h+1];for(f=this.u.length-1;0<=f;--f){var m=this.j[f];a.uniform4fv(this.v.B,m[0]);Ii(this,a,m[1],m[2]);for(g=this.u[f];0<=h&&this.i[h]>=g;){m=this.i[h];var n=this.f[h];var p=w(n).toString();if(void 0===c[p]&&n.V()&&(void 0===e||qb(e,n.V().G()))&&(a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT),xi(a,b,m,l),l=d(n)))return l;h--;l=m}}};function Ii(a,b,c,d){b.uniform4fv(a.v.R,c);b.uniform1f(a.v.oa,d)} +k.Ma=function(a,b){if(b){var c=b.i;this.c.lineDash=c?c:zi;c=b.g;this.c.lineDashOffset=c?c:0;c=b.a;c instanceof CanvasGradient||c instanceof CanvasPattern?c=Ai:c=ed(c).map(function(a,b){return 3!=b?a/255:a})||Ai;b=b.c;b=void 0!==b?b:1}else c=[0,0,0,0],b=0;a=a?a.b:[0,0,0,0];a instanceof CanvasGradient||a instanceof CanvasPattern?a=yi:a=ed(a).map(function(a,b){return 3!=b?a/255:a})||yi;this.c.strokeColor&&pa(this.c.strokeColor,c)&&this.c.fillColor&&pa(this.c.fillColor,a)&&this.c.lineWidth===b||(this.c.s= +!0,this.c.fillColor=a,this.c.strokeColor=c,this.c.lineWidth=b,this.j.push([a,c,b]))};function Ji(){this.b="precision mediump float;varying vec2 a;varying float b;uniform float k;uniform sampler2D l;void main(void){vec4 texColor=texture2D(l,a);gl_FragColor.rgb=texColor.rgb;float alpha=texColor.a*b*k;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}"}v(Ji,mi);var Ki=new Ji; +function Li(){this.b="varying vec2 a;varying float b;attribute vec2 c;attribute vec2 d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;void main(void){mat4 offsetMatrix=i;if(g==1.0){offsetMatrix=i*j;}vec4 offsets=offsetMatrix*vec4(e,0.0,0.0);gl_Position=h*vec4(c,0.0,1.0)+offsets;a=d;b=f;}"}v(Li,ni);var Mi=new Li; +function Ni(a,b){this.c=a.getUniformLocation(b,"j");this.f=a.getUniformLocation(b,"i");this.a=a.getUniformLocation(b,"k");this.i=a.getUniformLocation(b,"h");this.v=a.getAttribLocation(b,"e");this.u=a.getAttribLocation(b,"f");this.b=a.getAttribLocation(b,"c");this.D=a.getAttribLocation(b,"g");this.C=a.getAttribLocation(b,"d")};function Oi(a,b){this.j=a;this.b=b;this.a={};this.c={};this.i={};this.l=this.v=this.f=this.o=null;(this.g=ja(fa,"OES_element_index_uint"))&&b.getExtension("OES_element_index_uint");y(this.j,"webglcontextlost",this.Xo,this);y(this.j,"webglcontextrestored",this.Yo,this)}v(Oi,Mc); +function wi(a,b,c){var d=a.b,e=c.b,f=String(w(c));if(f in a.a)d.bindBuffer(b,a.a[f].buffer);else{var g=d.createBuffer();d.bindBuffer(b,g);var h;34962==b?h=new Float32Array(e):34963==b&&(h=a.g?new Uint32Array(e):new Uint16Array(e));d.bufferData(b,h,c.a);a.a[f]={lc:c,buffer:g}}}function Gi(a,b){var c=a.b;b=String(w(b));var d=a.a[b];c.isContextLost()||c.deleteBuffer(d.buffer);delete a.a[b]}k=Oi.prototype; +k.ka=function(){Lc(this.j);var a=this.b;if(!a.isContextLost()){for(var b in this.a)a.deleteBuffer(this.a[b].buffer);for(b in this.i)a.deleteProgram(this.i[b]);for(b in this.c)a.deleteShader(this.c[b]);a.deleteFramebuffer(this.f);a.deleteRenderbuffer(this.l);a.deleteTexture(this.v)}};k.Wo=function(){return this.b}; +function Pi(a){if(!a.f){var b=a.b,c=b.createFramebuffer();b.bindFramebuffer(b.FRAMEBUFFER,c);var d=Qi(b,1,1),e=b.createRenderbuffer();b.bindRenderbuffer(b.RENDERBUFFER,e);b.renderbufferStorage(b.RENDERBUFFER,b.DEPTH_COMPONENT16,1,1);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,d,0);b.framebufferRenderbuffer(b.FRAMEBUFFER,b.DEPTH_ATTACHMENT,b.RENDERBUFFER,e);b.bindTexture(b.TEXTURE_2D,null);b.bindRenderbuffer(b.RENDERBUFFER,null);b.bindFramebuffer(b.FRAMEBUFFER,null);a.f=c; +a.v=d;a.l=e}return a.f}function Ri(a,b){var c=String(w(b));if(c in a.c)return a.c[c];var d=a.b,e=d.createShader(b.U());d.shaderSource(e,b.b);d.compileShader(e);return a.c[c]=e}function Hi(a,b,c){var d=w(b)+"/"+w(c);if(d in a.i)return a.i[d];var e=a.b,f=e.createProgram();e.attachShader(f,Ri(a,b));e.attachShader(f,Ri(a,c));e.linkProgram(f);return a.i[d]=f}k.Xo=function(){ub(this.a);ub(this.c);ub(this.i);this.l=this.v=this.f=this.o=null};k.Yo=function(){}; +k.Qc=function(a){if(a==this.o)return!1;this.b.useProgram(a);this.o=a;return!0};function Si(a,b,c){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR);void 0!==b&&a.texParameteri(3553,10242,b);void 0!==c&&a.texParameteri(3553,10243,c);return d}function Qi(a,b,c){var d=Si(a,void 0,void 0);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,b,c,0,a.RGBA,a.UNSIGNED_BYTE,null);return d} +function Ti(a,b){var c=Si(a,33071,33071);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b);return c};function Ui(a,b){vi.call(this,0,b);this.C=this.D=void 0;this.S=[];this.v=[];this.oa=void 0;this.j=[];this.c=[];this.I=this.ra=void 0;this.B=null;this.fb=this.fa=this.na=this.T=this.Ua=this.R=void 0;this.va=[];this.u=[];this.pa=void 0}v(Ui,vi);k=Ui.prototype;k.Eb=function(a){var b=this.l,c=this.o,d=this.va,e=this.u,f=a.b;return function(){if(!f.isContextLost()){var g;var h=0;for(g=d.length;h=l;){var m=this.i[h];var n=this.f[h];var p=w(n).toString();if(void 0===c[p]&&n.V()&&(void 0===e||qb(e,n.V().G()))&&(a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT),xi(a,b,m,g),g=d(n)))return g;g=m;h--}}}; +k.Ub=function(a){var b=a.Hc(),c=a.Y(1),d=a.ye(),e=a.qg(1),f=a.f,g=a.Oc(),h=a.l,l=a.g,m=a.ic();a=a.a;if(this.j.length){var n=this.j[this.j.length-1];w(n)!=w(c)&&(this.S.push(this.b.length),this.j.push(c))}else this.j.push(c);this.c.length?(n=this.c[this.c.length-1],w(n)!=w(e)&&(this.v.push(this.b.length),this.c.push(e))):this.c.push(e);this.D=b[0];this.C=b[1];this.oa=m[1];this.ra=d[1];this.I=d[0];this.R=f;this.Ua=g[0];this.T=g[1];this.fa=l;this.na=h;this.fb=a;this.pa=m[0]};function Xi(a,b,c){var d=b-c;return a[0]===a[d]&&a[1]===a[d+1]&&3<(b-0)/c?!!vf(a,0,b,c):!1};function Yi(){this.b="precision mediump float;varying float a;varying vec2 b;varying float c;uniform float m;uniform vec4 n;uniform vec2 o;uniform float p;void main(void){if(a>0.0){vec2 windowCoords=vec2((b.x+1.0)/2.0*o.x*p,(b.y+1.0)/2.0*o.y*p);if(length(windowCoords-gl_FragCoord.xy)>c*p){discard;}} gl_FragColor=n;float alpha=n.a*m;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}"}v(Yi,mi);var Zi=new Yi; +function $i(){this.b="varying float a;varying vec2 b;varying float c;attribute vec2 d;attribute vec2 e;attribute vec2 f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;bool nearlyEquals(in float value,in float ref){float epsilon=0.000000000001;return value>=ref-epsilon&&value<=ref+epsilon;}void alongNormal(out vec2 offset,in vec2 nextP,in float turnDir,in float direction){vec2 dirVect=nextP-e;vec2 normal=normalize(vec2(-turnDir*dirVect.y,turnDir*dirVect.x));offset=k/2.0*normal*direction;}void miterUp(out vec2 offset,out float round,in bool isRound,in float direction){float halfWidth=k/2.0;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=f-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;round=0.0;if(isRound){round=1.0;}else if(miterLength>l+k){offset=halfWidth*tmpNormal*direction;}} bool miterDown(out vec2 offset,in vec4 projPos,in mat4 offsetMatrix,in float direction){bool degenerate=false;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=d-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));vec2 longOffset,shortOffset,longVertex;vec4 shortProjVertex;float halfWidth=k/2.0;if(length(f-e)>length(d-e)){longOffset=tmpNormal*direction*halfWidth;shortOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=f;shortProjVertex=h*vec4(d,0.0,1.0);}else{shortOffset=tmpNormal*direction*halfWidth;longOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=d;shortProjVertex=h*vec4(f,0.0,1.0);}vec4 p1=h*vec4(longVertex,0.0,1.0)+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p2=projPos+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p3=shortProjVertex+offsetMatrix*vec4(-shortOffset,0.0,0.0);vec4 p4=shortProjVertex+offsetMatrix*vec4(shortOffset,0.0,0.0);float denom=(p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y);float firstU=((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/denom;float secondU=((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/denom;float epsilon=0.000000000001;if(firstU>epsilon&&firstU<1.0-epsilon&&secondU>epsilon&&secondU<1.0-epsilon){shortProjVertex.x=p1.x+firstU*(p2.x-p1.x);shortProjVertex.y=p1.y+firstU*(p2.y-p1.y);offset=shortProjVertex.xy;degenerate=true;}else{float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;}return degenerate;}void squareCap(out vec2 offset,out float round,in bool isRound,in vec2 nextP,in float turnDir,in float direction){round=0.0;vec2 dirVect=e-nextP;vec2 firstNormal=normalize(dirVect);vec2 secondNormal=vec2(turnDir*firstNormal.y*direction,-turnDir*firstNormal.x*direction);vec2 hypotenuse=normalize(firstNormal-secondNormal);vec2 normal=vec2(turnDir*hypotenuse.y*direction,-turnDir*hypotenuse.x*direction);float length=sqrt(c*c*2.0);offset=normal*length;if(isRound){round=1.0;}} void main(void){bool degenerate=false;float direction=float(sign(g));mat4 offsetMatrix=i*j;vec2 offset;vec4 projPos=h*vec4(e,0.0,1.0);bool round=nearlyEquals(mod(g,2.0),0.0);a=0.0;c=k/2.0;b=projPos.xy;if(nearlyEquals(mod(g,3.0),0.0)||nearlyEquals(mod(g,17.0),0.0)){alongNormal(offset,f,1.0,direction);}else if(nearlyEquals(mod(g,5.0),0.0)||nearlyEquals(mod(g,13.0),0.0)){alongNormal(offset,d,-1.0,direction);}else if(nearlyEquals(mod(g,23.0),0.0)){miterUp(offset,a,round,direction);}else if(nearlyEquals(mod(g,19.0),0.0)){degenerate=miterDown(offset,projPos,offsetMatrix,direction);}else if(nearlyEquals(mod(g,7.0),0.0)){squareCap(offset,a,round,f,1.0,direction);}else if(nearlyEquals(mod(g,11.0),0.0)){squareCap(offset,a,round,d,-1.0,direction);}if(!degenerate){vec4 offsets=offsetMatrix*vec4(offset,0.0,0.0);gl_Position=projPos+offsets;}else{gl_Position=vec4(offset,0.0,1.0);}}"} +v($i,ni);var aj=new $i;function bj(a,b){this.B=a.getUniformLocation(b,"n");this.oa=a.getUniformLocation(b,"k");this.R=a.getUniformLocation(b,"l");this.c=a.getUniformLocation(b,"j");this.f=a.getUniformLocation(b,"i");this.a=a.getUniformLocation(b,"m");this.ra=a.getUniformLocation(b,"p");this.i=a.getUniformLocation(b,"h");this.I=a.getUniformLocation(b,"o");this.g=a.getAttribLocation(b,"g");this.o=a.getAttribLocation(b,"d");this.l=a.getAttribLocation(b,"f");this.b=a.getAttribLocation(b,"e")};function cj(a,b){vi.call(this,0,b);this.v=null;this.u=[];this.j=[];this.c={strokeColor:null,lineCap:void 0,lineDash:null,lineDashOffset:void 0,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0,s:!1}}v(cj,vi); +function dj(a,b,c,d){var e,f=a.a.length,g=a.b.length,h="bevel"===a.c.lineJoin?0:"miter"===a.c.lineJoin?1:2,l="butt"===a.c.lineCap?0:"square"===a.c.lineCap?1:2,m=Xi(b,c,d),n=g,p=1;for(e=0;ec&&(this.i.push(c),this.f.push(b),this.c.s&&(this.j.push(c),this.c.s=!1))}; +function oj(a,b,c,d){Xi(b,b.length,d)||(b.push(b[0]),b.push(b[1]));dj(a,b,b.length,d);if(c.length){var e;b=0;for(e=c.length;b=n;){var p=this.i[m]; +var q=this.f[m];q=w(q).toString();c[q]&&(g!==l&&(xi(a,b,g,l),a.clear(a.DEPTH_BUFFER_BIT)),l=p);m--;g=p}g!==l&&(xi(a,b,g,l),a.clear(a.DEPTH_BUFFER_BIT));g=l=n}}d||(a.disable(a.DEPTH_TEST),a.clear(a.DEPTH_BUFFER_BIT),a.depthMask(f),a.depthFunc(e))}; +k.ve=function(a,b,c,d,e){var f,g;var h=this.i.length-2;var l=this.i[h+1];for(f=this.j.length-1;0<=f;--f){var m=this.u[f];qj(this,a,m[0],m[1],m[2]);for(g=this.j[f];0<=h&&this.i[h]>=g;){m=this.i[h];var n=this.f[h];var p=w(n).toString();if(void 0===c[p]&&n.V()&&(void 0===e||qb(e,n.V().G()))&&(a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT),xi(a,b,m,l),l=d(n)))return l;h--;l=m}}};function qj(a,b,c,d,e){b.uniform4fv(a.v.B,c);b.uniform1f(a.v.oa,d);b.uniform1f(a.v.R,e)} +k.Ma=function(a,b){a=b.f;this.c.lineCap=void 0!==a?a:"round";a=b.i;this.c.lineDash=a?a:zi;a=b.g;this.c.lineDashOffset=a?a:0;a=b.j;this.c.lineJoin=void 0!==a?a:"round";a=b.a;a instanceof CanvasGradient||a instanceof CanvasPattern?a=Ai:a=ed(a).map(function(a,b){return 3!=b?a/255:a})||Ai;var c=b.c,c=void 0!==c?c:1;b=b.o;b=void 0!==b?b:10;this.c.strokeColor&&pa(this.c.strokeColor,a)&&this.c.lineWidth===c&&this.c.miterLimit===b||(this.c.s=!0,this.c.strokeColor=a,this.c.lineWidth=c,this.c.miterLimit=b, +this.u.push([a,c,b]))};var ij=3,fj=5,hj=7,gj=11,jj=13,kj=17,lj=19,mj=23;function rj(){this.b="precision mediump float;uniform vec4 e;uniform float f;void main(void){gl_FragColor=e;float alpha=e.a*f;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}"}v(rj,mi);var sj=new rj;function tj(){this.b="attribute vec2 a;uniform mat4 b;uniform mat4 c;uniform mat4 d;void main(void){gl_Position=b*vec4(a,0.0,1.0);}"}v(tj,ni);var uj=new tj; +function vj(a,b){this.B=a.getUniformLocation(b,"e");this.c=a.getUniformLocation(b,"d");this.f=a.getUniformLocation(b,"c");this.a=a.getUniformLocation(b,"f");this.i=a.getUniformLocation(b,"b");this.b=a.getAttribLocation(b,"a")};function wj(a){a=a||{};this.a=void 0!==a.color?a.color:null;this.f=a.lineCap;this.i=void 0!==a.lineDash?a.lineDash:null;this.g=a.lineDashOffset;this.j=a.lineJoin;this.o=a.miterLimit;this.c=a.width;this.b=void 0}k=wj.prototype;k.clone=function(){var a=this.a;return new wj({color:a&&a.slice?a.slice():a||void 0,lineCap:this.f,lineDash:this.i?this.i.slice():void 0,lineDashOffset:this.g,lineJoin:this.j,miterLimit:this.o,width:this.c})};k.No=function(){return this.a};k.Vk=function(){return this.f}; +k.Oo=function(){return this.i};k.Wk=function(){return this.g};k.Xk=function(){return this.j};k.bl=function(){return this.o};k.Po=function(){return this.c};k.Qo=function(a){this.a=a;this.b=void 0};k.aq=function(a){this.f=a;this.b=void 0};k.setLineDash=function(a){this.i=a;this.b=void 0};k.bq=function(a){this.g=a;this.b=void 0};k.cq=function(a){this.j=a;this.b=void 0};k.gq=function(a){this.o=a;this.b=void 0};k.jq=function(a){this.c=a;this.b=void 0};function xj(a){this.b=this.a=this.i=void 0;this.f=void 0===a?!0:a;this.c=0}function yj(a){var b=a.b;if(b){var c=b.next,d=b.ub;c&&(c.ub=d);d&&(d.next=c);a.b=c||d;a.i===a.a?(a.b=void 0,a.i=void 0,a.a=void 0):a.i===b?a.i=a.b:a.a===b&&(a.a=d?a.b.ub:a.b);a.c--}}function zj(a){a.b=a.i;if(a.b)return a.b.data}function Aj(a){if(a.b&&a.b.next)return a.b=a.b.next,a.b.data}function Bj(a){if(a.b&&a.b.next)return a.b.next.data}function Cj(a){if(a.b&&a.b.ub)return a.b=a.b.ub,a.b.data} +function Dj(a){if(a.b&&a.b.ub)return a.b.ub.data}function Ej(a){if(a.b)return a.b.data}xj.prototype.concat=function(a){if(a.b){if(this.b){var b=this.b.next;this.b.next=a.i;a.i.ub=this.b;b.ub=a.a;a.a.next=b;this.c+=a.c}else this.b=a.b,this.i=a.i,this.a=a.a,this.c=a.c;a.b=void 0;a.i=void 0;a.a=void 0;a.c=0}};var Fj={$d:function(){}}; +(function(a){function b(a,e,f,g,h){f=f||0;g=g||a.length-1;for(h=h||d;g>f;){if(600m-l/2?-1:1);b(a,e,Math.max(f,Math.floor(e-m*p/l+n)),Math.min(g,Math.floor(e+(l-m)*p/l+n)),h)}l=a[e];m=f;p=g;c(a,f,e);for(0h(a[m],l);)m++;for(;0b?1:0}function e(a,b){if(!(this instanceof e))return new e(a,b);this.Hf=Math.max(4,a||9);this.fh=Math.max(2,Math.ceil(.4*this.Hf));b&&this.ek(b);this.clear()}function f(a,b){g(a,0,a.children.length,b,a)}function g(a,b,c,d,e){e||(e=u(null));e.ca=Infinity;e.da=Infinity;e.$=-Infinity;e.ia=-Infinity;for(var f;b=a.ca&&b.ia>=a.da}function u(a){return{children:a,height:1,ib:!0,ca:Infinity,da:Infinity,$:-Infinity,ia:-Infinity}}function x(a,b,c,d,e){for(var f=[b,c],g;f.length;)c=f.pop(),b=f.pop(),c-b<=d||(g=b+Math.ceil((c-b)/d/2)*d,B(a,g,b,c,e),f.push(b,g, +g,c))}var B=b;e.prototype={all:function(){return this.$g(this.data,[])},search:function(a){var b=this.data,c=[],d=this.wb;if(!r(a,b))return c;for(var e=[],f,g,h,l;b;){f=0;for(g=b.children.length;fthis.Hf)this.jk(d,b),b--;else break;this.Zj(c,d,b)},jk:function(a,b){var c=a[b],d=c.children.length,e=this.fh;this.$j(c,e,d);d=this.ak(c,e,d);d=u(c.children.splice(d,c.children.length-d));d.height=c.height;d.ib=c.ib;f(c,this.wb);f(d,this.wb); +b?a[b-1].children.push(d):this.hh(c,d)},hh:function(a,b){this.data=u([a,b]);this.data.height=a.height+1;this.data.ib=!1;f(this.data,this.wb)},ak:function(a,b,c){var d,e;var f=e=Infinity;for(d=b;d<=c-b;d++){var h=g(a,0,d,this.wb);var l=g(a,d,c,this.wb);var m=Math.max(0,Math.min(h.$,l.$)-Math.max(h.ca,l.ca))*Math.max(0,Math.min(h.ia,l.ia)-Math.max(h.da,l.da));h=n(h)+n(l);if(m=b;m--)n=a.children[m],h(f,a.ib?d(n):n),l+=p(f);return l},Zj:function(a,b,c){for(;0<=c;c--)h(b[c],a)},ck:function(a){for(var b=a.length-1,c;0<=b;b--)0===a[b].children.length?0f&&(f=b[r],q=b[r+1]);p=u}}else for(r=b.length-c,p=l=Tj(a,b[r],b[r+1],h++),f=b[r],q=b[r+1],r-=c,g=0;r>=g;r-=c)u=Tj(a,b[r],b[r+1],h++),n.push(Uj(p,u,d)),m.push([Math.min(p.x,u.x),Math.min(p.y,u.y),Math.max(p.x, +u.x),Math.max(p.y,u.y)]),b[r]>f&&(f=b[r],q=b[r+1]),p=u;n.push(Uj(u,l,d));m.push([Math.min(p.x,u.x),Math.min(p.y,u.y),Math.max(p.x,u.x),Math.max(p.y,u.y)]);e.load(m,n);return[f,q]}function Qj(a,b,c){var d=zj(a),e=d,f=Aj(a),g=!1;do{var h=c?Bi(f.W.x,f.W.y,e.W.x,e.W.y,e.aa.x,e.aa.y):Bi(e.aa.x,e.aa.y,e.W.x,e.W.y,f.W.x,f.W.y);void 0===h?(Vj(e,f,a,b),g=!0,f===d&&(d=Bj(a)),f=e,Cj(a)):e.W.Fb!==h&&(e.W.Fb=h,g=!0);e=f;f=Aj(a)}while(e!==d);return g} +function Rj(a,b,c,d,e){for(var f=zj(a);f.W.x!==b;)f=Aj(a);b=f.W;d={x:d,y:b.y,hb:-1};var g=Infinity,h;var l=Pj({aa:b,W:d},e,!0);var m=0;for(h=l.length;mCi&&d<1-Ci&&c>Ci&&c<1-Ci||e&&0<=d&&1>=d&&0<=c&&1>=c))return[a.x+d*(b.x-a.x),a.y+d*(b.y-a.y)]} +function bk(a,b,c,d,e){if(void 0===b.Fb||void 0===d.Fb)return!1;var f=(c.x-d.x)*(b.y-d.y)>(c.y-d.y)*(b.x-d.x);e=(e.x-d.x)*(b.y-d.y)<(e.y-d.y)*(b.x-d.x);a=(a.x-b.x)*(d.y-b.y)>(a.y-b.y)*(d.x-b.x);c=(c.x-b.x)*(d.y-b.y)<(c.y-b.y)*(d.x-b.x);b=b.Fb?c||a:c&&a;return(d.Fb?e||f:e&&f)&&b}k=Mj.prototype; +k.pc=function(a,b){var c=a.c,d=a.qa(),e=this.b.length,f=this.g.b.length;a=a.ga();var g,h,l;var m=h=0;for(g=c.length;me&&(this.i.push(e),this.f.push(b),this.j.s&&(this.c.push(e),this.j.s=!1));this.g.b.length>f&&pj(this.g, +b,f)};k.rc=function(a,b){var c=a.Bb(),d=a.qa();if(0=n;){var p=this.i[m];var q=this.f[m];q=w(q).toString(); +c[q]&&(g!==l&&(xi(a,b,g,l),a.clear(a.DEPTH_BUFFER_BIT)),l=p);m--;g=p}g!==l&&(xi(a,b,g,l),a.clear(a.DEPTH_BUFFER_BIT));g=l=n}}d||(a.disable(a.DEPTH_TEST),a.clear(a.DEPTH_BUFFER_BIT),a.depthMask(f),a.depthFunc(e))}; +k.ve=function(a,b,c,d,e){var f,g;var h=this.i.length-2;var l=this.i[h+1];for(f=this.c.length-1;0<=f;--f){var m=this.u[f];a.uniform4fv(this.v.B,m);for(g=this.c[f];0<=h&&this.i[h]>=g;){m=this.i[h];var n=this.f[h];var p=w(n).toString();if(void 0===c[p]&&n.V()&&(void 0===e||qb(e,n.V().G()))&&(a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT),xi(a,b,m,l),l=d(n)))return l;h--;l=m}}}; +k.Ma=function(a,b){a=a?a.b:[0,0,0,0];a instanceof CanvasGradient||a instanceof CanvasPattern?a=yi:a=ed(a).map(function(a,b){return 3!=b?a/255:a})||yi;this.j.fillColor&&pa(a,this.j.fillColor)||(this.j.fillColor=a,this.j.s=!0,this.u.push(a));b?this.g.Ma(null,b):this.g.Ma(null,new wj({color:[0,0,0,0],lineWidth:0}))};function ck(){}ck.prototype.La=function(){};function dk(a,b,c){this.f=b;this.g=a;this.c=c;this.a={}}v(dk,ki);function ek(a,b){var c=[],d;for(d in a.a){var e=a.a[d],f;for(f in e)c.push(e[f].Eb(b))}return function(){for(var a=c.length,b,d=0;dd?b[0]=d-c:0>e&&(b[0]=Math.abs(e)+c),0>f?b[1]=f-c:0>g&&(b[1]=Math.abs(g)+c),0===b[0]&&0===b[1])|| +(c=a.Z().wa(),c=a.Ja(c),b=[c[0]+b[0],c[1]+b[1]],a.Z().animate({center:a.Wa(b),duration:this.j.duration,easing:this.j.easing}))}}};k.Ql=function(){yk(this)};k.lj=function(a){this.set(tk,a)};k.setMap=function(a){this.set(uk,a)};k.rj=function(a){this.set(vk,a)};k.Ne=function(a){this.set(wk,a)};function zk(a,b){var c=a.getBoundingClientRect();a=c.left+window.pageXOffset;c=c.top+window.pageYOffset;return[a,c,a+b[0],c+b[1]]}k.uj=function(a){this.set(xk,a)}; +function Ak(a,b){a.a.visible!==b&&(a.c.style.display=b?"":"none",a.a.visible=b)} +function yk(a){var b=a.Me(),c=a.Yh();if(b&&b.c&&c){var c=b.Ja(c),d=b.Ob(),b=a.c.style,e=a.Dh(),f=a.Eh();Ak(a,!0);var g=e[0],e=e[1];if("bottom-right"==f||"center-right"==f||"top-right"==f)""!==a.a.Ie&&(a.a.Ie=b.left=""),g=Math.round(d[0]-c[0]-g)+"px",a.a.nf!=g&&(a.a.nf=b.right=g);else{""!==a.a.nf&&(a.a.nf=b.right="");if("bottom-center"==f||"center-center"==f||"top-center"==f)g-=a.c.offsetWidth/2;g=Math.round(c[0]+g)+"px";a.a.Ie!=g&&(a.a.Ie=b.left=g)}if("bottom-left"==f||"bottom-center"==f||"bottom-right"== +f)""!==a.a.vf&&(a.a.vf=b.top=""),c=Math.round(d[1]-c[1]-e)+"px",a.a.re!=c&&(a.a.re=b.bottom=c);else{""!==a.a.re&&(a.a.re=b.bottom="");if("center-left"==f||"center-center"==f||"center-right"==f)e-=a.c.offsetHeight/2;c=Math.round(c[1]+e)+"px";a.a.vf!=c&&(a.a.vf=b.top=c)}}else Ak(a,!1)}var tk="element",uk="map",vk="offset",wk="position",xk="positioning";function Bk(a){function b(a){a=h.Tf(a);l.a.Z().ob(a);window.removeEventListener("mousemove",c);window.removeEventListener("mouseup",b)}function c(a){a=h.Tf({clientX:a.clientX-n.offsetWidth/2,clientY:a.clientY+n.offsetHeight/2});m.Ne(a)}a=a?a:{};this.j=void 0!==a.collapsed?a.collapsed:!0;this.o=void 0!==a.collapsible?a.collapsible:!0;this.o||(this.j=!1);var d=void 0!==a.className?a.className:"ol-overviewmap",e=void 0!==a.tipLabel?a.tipLabel:"Overview map",f=void 0!==a.collapseLabel?a.collapseLabel: +"\u00ab";"string"===typeof f?(this.u=document.createElement("span"),this.u.textContent=f):this.u=f;f=void 0!==a.label?a.label:"\u00bb";"string"===typeof f?(this.D=document.createElement("span"),this.D.textContent=f):this.D=f;var g=this.o&&!this.j?this.u:this.D,f=document.createElement("button");f.setAttribute("type","button");f.title=e;f.appendChild(g);y(f,"click",this.an,this);this.C=document.createElement("DIV");this.C.className="ol-overviewmap-map";var h=this.c=new G({controls:new Yc,interactions:new Yc, +view:a.view});a.layers&&a.layers.forEach(function(a){h.ih(a)},this);e=document.createElement("DIV");e.className="ol-overviewmap-box";e.style.boxSizing="border-box";this.l=new sk({position:[0,0],positioning:"bottom-left",element:e});this.c.jh(this.l);e=document.createElement("div");e.className=d+" ol-unselectable ol-control"+(this.j&&this.o?" ol-collapsed":"")+(this.o?"":" ol-uncollapsible");e.appendChild(this.C);e.appendChild(f);md.call(this,{element:e,render:a.render?a.render:Ck,target:a.target}); +var l=this,m=this.l,n=this.l.Rd();n.addEventListener("mousedown",function(){window.addEventListener("mousemove",c);window.addEventListener("mouseup",b)})}v(Bk,md);k=Bk.prototype;k.setMap=function(a){var b=this.a;a!==b&&(b&&((b=b.Z())&&Kc(b,Vc("rotation"),this.Ge,this),this.c.Le(null)),md.prototype.setMap.call(this,a),a&&(this.c.Le(this.C),this.v.push(y(a,"propertychange",this.Kl,this)),this.c.Xh().dc()||this.c.qj(a.Kc()),a=a.Z()))&&(y(a,Vc("rotation"),this.Ge,this),jg(a)&&(this.c.Ad(),Dk(this)))}; +k.Kl=function(a){"view"===a.key&&((a=a.oldValue)&&Kc(a,Vc("rotation"),this.Ge,this),a=this.a.Z(),y(a,Vc("rotation"),this.Ge,this))};k.Ge=function(){this.c.Z().Oe(this.a.Z().Qa())};function Ck(){var a=this.a,b=this.c;if(a.c&&b.c){var c=a.Ob(),a=a.Z().dd(c),d=b.Ob(),c=b.Z().dd(d),e=b.Ja(ib(a)),f=b.Ja(gb(a)),b=Math.abs(e[0]-f[0]),e=Math.abs(e[1]-f[1]),f=d[0],d=d[1];b<.1*f||e<.1*d||b>.75*f||e>.75*d?Dk(this):Va(c,a)||(a=this.c,c=this.a.Z(),a.Z().ob(c.wa()))}Ek(this)} +function Dk(a){var b=a.a;a=a.c;var c=b.Ob(),b=b.Z().dd(c);a=a.Z();rb(b,1/(.1*Math.pow(2,Math.log(7.5)/Math.LN2/2)));a.Qf(b)}function Ek(a){var b=a.a,c=a.c;if(b.c&&c.c){var d=b.Ob(),e=b.Z(),f=c.Z(),c=e.Qa(),b=a.l,g=a.l.Rd(),h=e.dd(d),d=f.Pa(),e=eb(h),f=hb(h);if(a=a.a.Z().wa()){var l=[e[0]-a[0],e[1]-a[1]];ef(l,c);Ze(l,a)}b.Ne(l);g&&(g.style.width=Math.abs((e[0]-f[0])/d)+"px",g.style.height=Math.abs((f[1]-e[1])/d)+"px")}}k.an=function(a){a.preventDefault();Fk(this)}; +function Fk(a){a.element.classList.toggle("ol-collapsed");a.j?kd(a.u,a.D):kd(a.D,a.u);a.j=!a.j;var b=a.c;a.j||b.c||(b.Ad(),Dk(a),Jc(b,"postrender",function(){Ek(this)},a))}k.$m=function(){return this.o};k.cn=function(a){this.o!==a&&(this.o=a,this.element.classList.toggle("ol-uncollapsible"),!a&&this.j&&Fk(this))};k.bn=function(a){this.o&&this.j!==a&&Fk(this)};k.Zm=function(){return this.j};k.gl=function(){return this.c};function Gk(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-scale-line";this.o=document.createElement("DIV");this.o.className=b+"-inner";this.c=document.createElement("DIV");this.c.className=b+" ol-unselectable";this.c.appendChild(this.o);this.u=null;this.l=void 0!==a.minWidth?a.minWidth:64;this.j=!1;this.B=void 0;this.D="";md.call(this,{element:this.c,render:a.render?a.render:Hk,target:a.target});y(this,Vc(Ik),this.T,this);this.I(a.units||"metric")}v(Gk,md);var Jk=[1,2,5];Gk.prototype.C=function(){return this.get(Ik)}; +function Hk(a){(a=a.frameState)?this.u=a.viewState:this.u=null;Kk(this)}Gk.prototype.T=function(){Kk(this)};Gk.prototype.I=function(a){this.set(Ik,a)}; +function Kk(a){var b=a.u;if(b){var c=b.projection,d=c.sc(),b=Sb(c,b.resolution,b.center)*d,d=a.l*b,c="",e=a.C();"degrees"==e?(c=zb.degrees,b/=c,dd?(c="in",b/=.0254):1609.344>d?(c="ft",b/=.3048):(c="mi",b/=1609.344):"nautical"==e?(b/=1852,c="nm"):"metric"==e?.001>d?(c="\u03bcm",b*=1E6):1>d?(c="mm",b*=1E3):1E3>d?c="m":(c="km",b/=1E3):"us"==e?.9144>d?(c="in",b*=39.37):1609.344>d?(c="ft",b/=.30480061):(c="mi",b/=1609.3472): +xa(!1,33);for(var e=3*Math.floor(Math.log(a.l*b)/Math.log(10)),f;;){f=Jk[(e%3+3)%3]*Math.pow(10,Math.floor(e/3));d=Math.round(f/b);if(isNaN(d)){a.c.style.display="none";a.j=!1;return}if(d>=a.l)break;++e}b=f+" "+c;a.D!=b&&(a.o.innerHTML=b,a.D=b);a.B!=d&&(a.o.style.width=d+"px",a.B=d);a.j||(a.c.style.display="",a.j=!0)}else a.j&&(a.c.style.display="none",a.j=!1)}var Ik="units";function Lk(a){a=a?a:{};this.c=void 0;this.j=Mk;this.D=this.l=0;this.I=null;this.na=!1;this.T=void 0!==a.duration?a.duration:200;var b=void 0!==a.className?a.className:"ol-zoomslider",c=document.createElement("button");c.setAttribute("type","button");c.className=b+"-thumb ol-unselectable";var d=document.createElement("div");d.className=b+" ol-unselectable ol-control";d.appendChild(c);this.o=new Ae(d);y(this.o,"pointerdown",this.yl,this);y(this.o,"pointermove",this.wl,this);y(this.o,"pointerup",this.xl, +this);y(d,"click",this.vl,this);y(c,"click",Pc);md.call(this,{element:d,render:a.render?a.render:Nk})}v(Lk,md);Lk.prototype.ka=function(){Nc(this.o);md.prototype.ka.call(this)};var Mk=0;k=Lk.prototype;k.setMap=function(a){md.prototype.setMap.call(this,a);a&&a.render()}; +function Nk(a){if(a.frameState){if(!this.na){var b=this.element,c=b.offsetWidth,d=b.offsetHeight,e=b.firstElementChild,f=getComputedStyle(e),b=e.offsetWidth+parseFloat(f.marginRight)+parseFloat(f.marginLeft),e=e.offsetHeight+parseFloat(f.marginTop)+parseFloat(f.marginBottom);this.I=[b,e];c>d?(this.j=1,this.D=c-b):(this.j=Mk,this.l=d-e);this.na=!0}a=a.frameState.viewState.resolution;a!==this.c&&(this.c=a,Ok(this,a))}} +k.vl=function(a){var b=this.a.Z();a=Pk(this,Ca(1===this.j?(a.offsetX-this.I[0]/2)/this.D:(a.offsetY-this.I[1]/2)/this.l,0,1));b.animate({resolution:b.constrainResolution(a),duration:this.T,easing:rd})};k.yl=function(a){this.u||a.b.target!==this.element.firstElementChild||(cg(this.a.Z(),1,1),this.C=a.clientX,this.B=a.clientY,this.u=!0)}; +k.wl=function(a){if(this.u){var b=this.element.firstElementChild;this.c=Pk(this,Ca(1===this.j?(a.clientX-this.C+parseInt(b.style.left,10))/this.D:(a.clientY-this.B+parseInt(b.style.top,10))/this.l,0,1));this.a.Z().Vc(this.c);Ok(this,this.c);this.C=a.clientX;this.B=a.clientY}};k.xl=function(){if(this.u){var a=this.a.Z();cg(a,1,-1);a.animate({resolution:a.constrainResolution(this.c),duration:this.T,easing:rd});this.u=!1;this.B=this.C=void 0}}; +function Ok(a,b){b=1-ig(a.a.Z())(b);var c=a.element.firstElementChild;1==a.j?c.style.left=a.D*b+"px":c.style.top=a.l*b+"px"}function Pk(a,b){return hg(a.a.Z())(1-b)};function Qk(a){a=a?a:{};this.c=a.extent?a.extent:null;var b=void 0!==a.className?a.className:"ol-zoom-extent",c=void 0!==a.label?a.label:"E",d=void 0!==a.tipLabel?a.tipLabel:"Fit to extent",e=document.createElement("button");e.setAttribute("type","button");e.title=d;e.appendChild("string"===typeof c?document.createTextNode(c):c);y(e,"click",this.j,this);c=document.createElement("div");c.className=b+" ol-unselectable ol-control";c.appendChild(e);md.call(this,{element:c,target:a.target})}v(Qk,md); +Qk.prototype.j=function(a){a.preventDefault();a=this.a.Z();var b=this.c?this.c:a.v.G();a.Qf(b)};function Rk(a){Tc.call(this);a=a?a:{};this.a=null;y(this,Vc(Sk),this.vm,this);this.gg(void 0!==a.tracking?a.tracking:!1)}v(Rk,Tc);k=Rk.prototype;k.ka=function(){this.gg(!1);Tc.prototype.ka.call(this)}; +k.ap=function(a){if(null!==a.alpha){var b=Ha(a.alpha);this.set(Tk,b);"boolean"===typeof a.absolute&&a.absolute?this.set(Uk,b):"number"===typeof a.webkitCompassHeading&&-1!=a.webkitCompassAccuracy&&this.set(Uk,Ha(a.webkitCompassHeading))}null!==a.beta&&this.set(Vk,Ha(a.beta));null!==a.gamma&&this.set(Wk,Ha(a.gamma));this.s()};k.Fk=function(){return this.get(Tk)};k.Ik=function(){return this.get(Vk)};k.Ok=function(){return this.get(Wk)};k.um=function(){return this.get(Uk)};k.Th=function(){return this.get(Sk)}; +k.vm=function(){if(Vd){var a=this.Th();a&&!this.a?this.a=y(window,"deviceorientation",this.ap,this):a||null===this.a||(Ec(this.a),this.a=null)}};k.gg=function(a){this.set(Sk,a)};var Tk="alpha",Vk="beta",Wk="gamma",Uk="heading",Sk="tracking";function Xk(a){this.f=a.opacity;this.l=a.rotateWithView;this.g=a.rotation;this.a=a.scale;this.v=a.snapToPixel}k=Xk.prototype;k.Ze=function(){return this.f};k.$e=function(){return this.l};k.af=function(){return this.g};k.bf=function(){return this.a};k.Ae=function(){return this.v};k.td=function(a){this.f=a};k.cf=function(a){this.g=a};k.ud=function(a){this.a=a};function Yk(a){this.D=this.u=this.c=null;this.Va=void 0!==a.fill?a.fill:null;this.oa=[0,0];this.o=a.points;this.b=void 0!==a.radius?a.radius:a.radius1;this.i=a.radius2;this.j=void 0!==a.angle?a.angle:0;this.Ya=void 0!==a.stroke?a.stroke:null;this.B=this.ra=this.C=null;this.S=a.atlasManager;Zk(this,this.S);Xk.call(this,{opacity:1,rotateWithView:void 0!==a.rotateWithView?a.rotateWithView:!1,rotation:void 0!==a.rotation?a.rotation:0,scale:1,snapToPixel:void 0!==a.snapToPixel?a.snapToPixel:!0})} +v(Yk,Xk);k=Yk.prototype;k.clone=function(){var a=new Yk({fill:this.Fa()?this.Fa().clone():void 0,points:this.o,radius:this.b,radius2:this.i,angle:this.j,snapToPixel:this.v,stroke:this.Ga()?this.Ga().clone():void 0,rotation:this.g,rotateWithView:this.l,atlasManager:this.S});a.td(this.f);a.ud(this.a);return a};k.Hc=function(){return this.C};k.Pi=function(){return this.j};k.Fa=function(){return this.Va};k.qg=function(){return this.D};k.Y=function(){return this.u};k.ye=function(){return this.B}; +k.Ye=function(){return 2};k.Oc=function(){return this.oa};k.Qi=function(){return this.o};k.Ri=function(){return this.b};k.Fh=function(){return this.i};k.ic=function(){return this.ra};k.Ga=function(){return this.Ya};k.Nh=function(){};k.load=function(){};k.Bj=function(){}; +function Zk(a,b){var c="",d="",e=0,f=null,g=0;if(a.Ya){var h=a.Ya.a;null===h&&(h=Uh);h=id(h);g=a.Ya.c;void 0===g&&(g=1);f=a.Ya.i;Td||(f=null);d=a.Ya.j;void 0===d&&(d="round");c=a.Ya.f;void 0===c&&(c="round");e=a.Ya.o;void 0===e&&(e=10)}var l=2*(a.b+g)+1,c={strokeStyle:h,zj:g,size:l,lineCap:c,lineDash:f,lineJoin:d,miterLimit:e};if(void 0===b){var m=jd(l,l);a.u=m.canvas;b=l=a.u.width;a.rh(c,m,0,0);a.Va?a.D=a.u:(m=jd(c.size,c.size),a.D=m.canvas,a.qh(c,m,0,0))}else l=Math.round(l),(d=!a.Va)&&(m=a.qh.bind(a, +c)),a.Ya?(e=a.Ya,void 0===e.b&&(e.b="s",e.b=e.a?"string"===typeof e.a?e.b+e.a:e.b+w(e.a).toString():e.b+"-",e.b+=","+(void 0!==e.f?e.f.toString():"-")+","+(e.i?e.i.toString():"-")+","+(void 0!==e.g?e.g:"-")+","+(void 0!==e.j?e.j:"-")+","+(void 0!==e.o?e.o.toString():"-")+","+(void 0!==e.c?e.c.toString():"-")),e=e.b):e="-",a.Va?(f=a.Va,void 0===f.a&&(f.a=f.b instanceof CanvasPattern||f.b instanceof CanvasGradient?w(f.b).toString():"f"+(f.b?gd(f.b):"-")),f=f.a):f="-",a.c&&e==a.c[1]&&f==a.c[2]&&a.b== +a.c[3]&&a.i==a.c[4]&&a.j==a.c[5]&&a.o==a.c[6]||(a.c=["r"+e+f+(void 0!==a.b?a.b.toString():"-")+(void 0!==a.i?a.i.toString():"-")+(void 0!==a.j?a.j.toString():"-")+(void 0!==a.o?a.o.toString():"-"),e,f,a.b,a.i,a.j,a.o]),m=b.add(a.c[0],l,l,a.rh.bind(a,c),m),a.u=m.image,a.oa=[m.offsetX,m.offsetY],b=m.image.width,a.D=d?m.Zl:a.u;a.C=[l/2,l/2];a.ra=[l,l];a.B=[b,b]} +k.rh=function(a,b,c,d){b.setTransform(1,0,0,1,0,0);b.translate(c,d);b.beginPath();var e=this.o;if(Infinity===e)b.arc(a.size/2,a.size/2,this.b,0,2*Math.PI,!0);else{var f=void 0!==this.i?this.i:this.b;f!==this.b&&(e*=2);for(c=0;c<=e;c++){d=2*c*Math.PI/e-Math.PI/2+this.j;var g=c%2?f:this.b;b.lineTo(a.size/2+g*Math.cos(d),a.size/2+g*Math.sin(d))}}this.Va&&(c=this.Va.b,null===c&&(c=Sh),b.fillStyle=id(c),b.fill());this.Ya&&(b.strokeStyle=a.strokeStyle,b.lineWidth=a.zj,a.lineDash&&b.setLineDash(a.lineDash), +b.lineCap=a.lineCap,b.lineJoin=a.lineJoin,b.miterLimit=a.miterLimit,b.stroke());b.closePath()}; +k.qh=function(a,b,c,d){b.setTransform(1,0,0,1,0,0);b.translate(c,d);b.beginPath();c=this.o;if(Infinity===c)b.arc(a.size/2,a.size/2,this.b,0,2*Math.PI,!0);else{d=void 0!==this.i?this.i:this.b;d!==this.b&&(c*=2);var e;for(e=0;e<=c;e++){var f=2*e*Math.PI/c-Math.PI/2+this.j;var g=e%2?d:this.b;b.lineTo(a.size/2+g*Math.cos(f),a.size/2+g*Math.sin(f))}}b.fillStyle=Sh;b.fill();this.Ya&&(b.strokeStyle=a.strokeStyle,b.lineWidth=a.zj,a.lineDash&&b.setLineDash(a.lineDash),b.stroke());b.closePath()};function $k(a){a=a||{};Yk.call(this,{points:Infinity,fill:a.fill,radius:a.radius,snapToPixel:a.snapToPixel,stroke:a.stroke,atlasManager:a.atlasManager})}v($k,Yk);$k.prototype.clone=function(){var a=new $k({fill:this.Fa()?this.Fa().clone():void 0,stroke:this.Ga()?this.Ga().clone():void 0,radius:this.b,snapToPixel:this.v,atlasManager:this.S});a.td(this.f);a.ud(this.a);return a};$k.prototype.Uc=function(a){this.b=a;Zk(this,this.S)};function al(a){a=a||{};this.b=void 0!==a.color?a.color:null;this.a=void 0}al.prototype.clone=function(){var a=this.b;return new al({color:a&&a.slice?a.slice():a||void 0})};al.prototype.i=function(){return this.b};al.prototype.c=function(a){this.b=a;this.a=void 0};function bl(a){a=a||{};this.Gc=null;this.Za=cl;void 0!==a.geometry&&this.Ra(a.geometry);this.Va=void 0!==a.fill?a.fill:null;this.M=void 0!==a.image?a.image:null;this.Ya=void 0!==a.stroke?a.stroke:null;this.Ia=void 0!==a.text?a.text:null;this.Fj=a.zIndex}k=bl.prototype; +k.clone=function(){var a=this.V();a&&a.clone&&(a=a.clone());return new bl({geometry:a,fill:this.Fa()?this.Fa().clone():void 0,image:this.Y()?this.Y().clone():void 0,stroke:this.Ga()?this.Ga().clone():void 0,text:this.Na()?this.Na().clone():void 0,zIndex:this.Ba()})};k.V=function(){return this.Gc};k.Pk=function(){return this.Za};k.Fa=function(){return this.Va};k.pf=function(a){this.Va=a};k.Y=function(){return this.M};k.Og=function(a){this.M=a};k.Ga=function(){return this.Ya}; +k.qf=function(a){this.Ya=a};k.Na=function(){return this.Ia};k.xd=function(a){this.Ia=a};k.Ba=function(){return this.Fj};k.Ra=function(a){"function"===typeof a?this.Za=a:"string"===typeof a?this.Za=function(b){return b.get(a)}:a?a&&(this.Za=function(){return a}):this.Za=cl;this.Gc=a};k.Vb=function(a){this.Fj=a};function dl(a){if("function"!==typeof a){if(Array.isArray(a))var b=a;else xa(a instanceof bl,41),b=[a];a=function(){return b}}return a}var el=null; +function fl(){if(!el){var a=new al({color:"rgba(255,255,255,0.4)"}),b=new wj({color:"#3399CC",width:1.25});el=[new bl({image:new $k({fill:a,stroke:b,radius:5}),fill:a,stroke:b})]}return el} +function gl(){var a={},b=[255,255,255,1],c=[0,153,255,1];a.Polygon=[new bl({fill:new al({color:[255,255,255,.5]})})];a.MultiPolygon=a.Polygon;a.LineString=[new bl({stroke:new wj({color:b,width:5})}),new bl({stroke:new wj({color:c,width:3})})];a.MultiLineString=a.LineString;a.Circle=a.Polygon.concat(a.LineString);a.Point=[new bl({image:new $k({radius:6,fill:new al({color:c}),stroke:new wj({color:b,width:1.5})}),zIndex:Infinity})];a.MultiPoint=a.Point;a.GeometryCollection=a.Polygon.concat(a.LineString, +a.Point);return a}function cl(a){return a.V()};function H(a){Tc.call(this);this.a=void 0;this.c="geometry";this.g=null;this.j=void 0;this.f=null;y(this,Vc(this.c),this.Ee,this);void 0!==a&&(a instanceof of||!a?this.Ra(a):this.H(a))}v(H,Tc);k=H.prototype;k.clone=function(){var a=new H(this.N());a.Tc(this.c);var b=this.V();b&&a.Ra(b.clone());(b=this.g)&&a.hg(b);return a};k.V=function(){return this.get(this.c)};k.wm=function(){return this.a};k.Qk=function(){return this.c};k.xm=function(){return this.g};k.Lc=function(){return this.j};k.Al=function(){this.s()}; +k.Ee=function(){this.f&&(Ec(this.f),this.f=null);var a=this.V();a&&(this.f=y(a,"change",this.Al,this));this.s()};k.Ra=function(a){this.set(this.c,a)};k.hg=function(a){this.j=(this.g=a)?hl(a):void 0;this.s()};k.jc=function(a){this.a=a;this.s()};k.Tc=function(a){Kc(this,Vc(this.c),this.Ee,this);this.c=a;y(this,Vc(this.c),this.Ee,this);this.Ee()}; +function hl(a){var b;if("function"===typeof a)2==a.length?b=function(b){return a(this,b)}:b=a;else{if(Array.isArray(a))var c=a;else xa(a instanceof bl,41),c=[a];b=function(){return c}}return b};var il=document.implementation.createDocument("","",null);function jl(a,b){return il.createElementNS(a,b)}function kl(a,b){return ll(a,b,[]).join("")}function ll(a,b,c){if(a.nodeType==Node.CDATA_SECTION_NODE||a.nodeType==Node.TEXT_NODE)b?c.push(String(a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):c.push(a.nodeValue);else for(a=a.firstChild;a;a=a.nextSibling)ll(a,b,c);return c}function ml(a){return a instanceof Document}function nl(a){return a instanceof Node} +function pl(a){return(new DOMParser).parseFromString(a,"application/xml")}function ql(a,b){return function(c,d){c=a.call(b,c,d);void 0!==c&&la(d[d.length-1],c)}}function rl(a,b){return function(c,d){c=a.call(void 0!==b?b:this,c,d);void 0!==c&&d[d.length-1].push(c)}}function sl(a,b){return function(c,d){c=a.call(void 0!==b?b:this,c,d);void 0!==c&&(d[d.length-1]=c)}} +function tl(a){return function(b,c){var d=a.call(this,b,c);if(void 0!==d){c=c[c.length-1];b=b.localName;var e;b in c?e=c[b]:e=c[b]=[];e.push(d)}}}function I(a,b){return function(c,d){var e=a.call(this,c,d);void 0!==e&&(d[d.length-1][void 0!==b?b:c.localName]=e)}}function J(a,b){return function(c,d,e){a.call(void 0!==b?b:this,c,d,e);e[e.length-1].node.appendChild(c)}} +function vl(a){var b,c;return function(d,e,f){if(!b){b={};var g={};g[d.localName]=a;b[d.namespaceURI]=g;c=wl(d.localName)}xl(b,c,e,f)}}function wl(a,b){return function(c,d,e){c=d[d.length-1].node;d=a;void 0===d&&(d=e);e=b;void 0===b&&(e=c.namespaceURI);return jl(e,d)}}var yl=wl();function zl(a,b){for(var c=b.length,d=Array(c),e=0;eh.status){var a=b.U();if("json"==a||"text"==a)var e=h.responseText;else"xml"==a?(e=h.responseXML)||(e=pl(h.responseText)):"arraybuffer"==a&&(e=h.response);e?c.call(this,b.Oa(e,{featureProjection:g}),b.kb(e)):d.call(this)}else d.call(this)}.bind(this);h.onerror=function(){d.call(this)}.bind(this); +h.send()}}function Dl(a,b){return Cl(a,b,function(a){this.cd(a)},ua)};function El(){this.f=this.defaultDataProjection=null}function Fl(a,b,c){var d;c&&(d={dataProjection:c.dataProjection?c.dataProjection:a.kb(b),featureProjection:c.featureProjection});return Gl(a,d)}function Gl(a,b){return tb({dataProjection:a.defaultDataProjection,featureProjection:a.f},b)} +function Hl(a,b,c){var d=c?Tb(c.featureProjection):null,e=c?Tb(c.dataProjection):null,f;d&&e&&!dc(d,e)?a instanceof of?f=(b?a.clone():a).tb(b?d:e,b?e:d):f=hc(a,e,d):f=a;if(b&&c&&void 0!==c.decimals){var g=Math.pow(10,c.decimals);f===a&&(f=f.clone());f.Dc(function(a){for(var b=0,c=a.length;b>1),h=+ia(g[e],c),0>h?l=e+1:(m=e,n=!h);e=n?l:~l;0>e?(c=(c-g[-e-2])/(g[-e-1]-g[-e-2]),b+=(-e-2)*d,g=Ja(a[b],a[b+d],c),h=Ja(a[b+1],a[b+d+1],c)):(g=a[b+e*d],h=a[b+e*d+1])}return f?(f[0]= +g,f[1]=h,f):[g,h]}function Ll(a,b,c,d,e,f){if(c==b)return null;if(e>1,ea||this.c.length<=a)return null;var b=new O(null);b.ba(this.ja,this.A.slice(a?this.c[a-1]:0,this.c[a]));return b}; +k.gd=function(){var a=this.A,b=this.c,c=this.ja,d=[],e=0,f;var g=0;for(f=b.length;ga||b<=a)return null;b=new C(null);b.ba(this.ja,this.A.slice(a*this.a,(a+1)*this.a));return b};k.Zd=function(){var a=this.A,b=this.ja,c=this.a,d=[],e;var f=0;for(e=a.length;fa||this.c.length<=a)return null;if(a){var b=this.c[a-1];b=b[b.length-1]}else b=0;a=this.c[a].slice();var c=a[a.length-1];if(b){var d;var e=0;for(d=a.length;ea||this.g&&ac;++c){var d=parseInt(b[c],10).toString(16);b[c]=1==d.length?"0"+d:d}Pm(a,b.join(""))}function wp(a,b,c){a={node:a};var d=b.U();if("GeometryCollection"==d){var e=b.Vf();var f=xp}else"MultiPoint"==d?(e=b.Zd(),f=yp):"MultiLineString"==d?(e=b.gd(),f=zp):"MultiPolygon"==d?(e=b.Td(),f=Ap):xa(!1,39);Bl(a,Bp,f,e,c)}function Cp(a,b,c){Bl({node:a},Dp,Ep,[b],c)} +function Fp(a,b,c){var d={node:a};b.a&&a.setAttribute("id",b.a);a=b.N();var e={address:1,description:1,name:1,open:1,phoneNumber:1,styleUrl:1,visibility:1};e[b.c]=1;var f=Object.keys(a||{}).sort().filter(function(a){return!e[a]});if(0>4;if(128>f)return d(a,g,b);f=e[c.ea++];g|=(f&127)<<3;if(128>f)return d(a,g,b);f=e[c.ea++];g|=(f&127)<<10;if(128>f)return d(a,g,b);f=e[c.ea++];g|=(f&127)<<17;if(128>f)return d(a,g,b);f=e[c.ea++];g|=(f&127)<<24;if(128>f)return d(a,g,b);f=e[c.ea++];if(128>f)return d(a,g|(f&1)<<31,b);throw Error("Expected varint not more than 10 bytes"); +}function d(a,b,c){return c?4294967296*b+(a>>>0):4294967296*(b>>>0)+(a>>>0)}var e={read:function(a,b,c,d,e){var f=8*e-d-1;var g=(1<>1,l=-7;e=c?e-1:0;var m=c?-1:1,x=a[b+e];e+=m;c=x&(1<<-l)-1;x>>=-l;for(l+=f;0>=-l;for(l+=d;0>1,m=23===e?Math.pow(2, +-24)-Math.pow(2,-77):0;n=d?0:n-1;var B=d?1:-1,E=0>b||0===b&&0>1/b?1:0;b=Math.abs(b);isNaN(b)||Infinity===b?(b=isNaN(b)?1:0,d=h):(d=Math.floor(Math.log(b)/Math.LN2),1>b*(f=Math.pow(2,-d))&&(d--,f*=2),b=1<=d+l?b+m/f:b+m*Math.pow(2,1-l),2<=b*f&&(d++,f/=2),d+l>=h?(b=0,d=h):1<=d+l?(b=(b*f-1)*Math.pow(2,e),d+=l):(b=b*Math.pow(2,l-1)*Math.pow(2,e),d=0));for(;8<=e;a[c+n]=b&255,n+=B,b/=256,e-=8);d=d<>3,f=this.ea;this.type=d&7;a(e,b,this);this.ea===f&&this.mq(d)}return b},yp:function(){var a=e.read(this.lc,this.ea,!0,23,4);this.ea+=4;return a},up:function(){var a=e.read(this.lc,this.ea,!0,52,8);this.ea+=8;return a},Ka:function(a){var b=this.lc;var d=b[this.ea++];var e=d&127;if(128>d)return e;d=b[this.ea++];e|=(d&127)<<7;if(128>d)return e;d=b[this.ea++];e|=(d&127)<<14;if(128>d)return e;d=b[this.ea++];e|=(d&127)<<21;if(128>d)return e;d=b[this.ea]; +return c(e|(d&15)<<28,a,this)},Kp:function(){return this.Ka(!0)},ce:function(){var a=this.Ka();return 1===a%2?(a+1)/-2:a/2},sp:function(){return!!this.Ka()},Gg:function(){for(var a=this.Ka()+this.ea,b=this.lc,c="",d=this.ea;da)break;if(1===p)128>e&&(n=e);else if(2===p){var q=b[d+1];128===(q&192)&&(n=(e&31)<<6|q&63,127>=n&&(n=null))}else if(3===p){q=b[d+1];var r=b[d+2];128===(q&192)&&128===(r&192)&&(n=(e&15)<<12|(q&63)<<6|r&63,2047>=n||55296<= +n&&57343>=n)&&(n=null)}else if(4===p){q=b[d+1];r=b[d+2];var u=b[d+3];128===(q&192)&&128===(r&192)&&128===(u&192)&&(n=(e&15)<<18|(q&63)<<12|(r&63)<<6|u&63,65535>=n||1114112<=n)&&(n=null)}null===n?(n=65533,p=1):65535>>10&1023|55296),n=56320|n&1023);c+=String.fromCharCode(n);d+=p}this.ea=a;return c},mq:function(a){a&=7;if(a===b.c)for(;127>3,b=1===b?a.Gg():2===b?a.yp():3===b?a.up():4===b?a.Kp():5===b?a.Ka():6===b?a.ce():7===b?a.sp():null;return b}function l(a,b,c){3===a&&(a=new m(c,c.Ka()+c.ea),a.length&&(b[a.name]=a))}c.prototype={clone:function(){return new c(this.x,this.y)},add:function(a){return this.clone().Yj(a)}, +rotate:function(a){return this.clone().hk(a)},round:function(){return this.clone().ik()},angle:function(){return Math.atan2(this.y,this.x)},Yj:function(a){this.x+=a.x;this.y+=a.y;return this},hk:function(a){var b=Math.cos(a);a=Math.sin(a);var c=a*this.x+b*this.y;this.x=b*this.x-a*this.y;this.y=c;return this},ik:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this}};c.Kq=function(a){return a instanceof c?a:Array.isArray(a)?new c(a[0],a[1]):a};d.b=["Unknown","Point","LineString", +"Polygon"];d.prototype.Oh=function(){var a=this.Cc;a.ea=this.Ef;for(var b=a.Ka()+a.ea,d=1,e=0,f=0,g=0,h=[],l;a.ea>=3),e--,1===d||2===d)f+=a.ce(),g+=a.ce(),1===d&&(l&&h.push(l),l=[]),l.push(new c(f,g));else if(7===d)l&&l.push(l[0].clone());else throw Error("unknown command "+d);l&&h.push(l);return h};d.prototype.bbox=function(){var a=this.Cc;a.ea=this.Ef;for(var b=a.Ka()+a.ea,c=1,d=0,e=0,f=0,g=Infinity,h=-Infinity,l=Infinity,m=-Infinity;a.ea>= +3),d--,1===c||2===c)e+=a.ce(),f+=a.ce(),eh&&(h=e),fm&&(m=f);else if(7!==c)throw Error("unknown command "+c);return[g,l,h,m]};var m=f;f.prototype.feature=function(a){if(0>a||a>=this.me.length)throw Error("feature index out of bounds");this.Cc.ea=this.me[a];a=this.Cc.Ka()+this.Cc.ea;return new d(this.Cc,a,this.extent,this.ne,this.pe)};var n=m;a["default"]={Bf:b,Wj:d,Xj:n};a.Bf=b;a.Wj=d;a.Xj=n})(Fj.xf=Fj.xf||{});function kq(a,b,c,d,e){this.g=e;this.i=a;this.b=b;this.f=c;this.c=d}k=kq.prototype;k.get=function(a){return this.c[a]};k.Bb=function(){return this.f};k.G=function(){this.a||(this.a="Point"===this.i?Za(this.b):$a(this.b,0,this.b.length,2));return this.a};k.Wn=function(){return this.g};k.ec=function(){return this.b};k.ga=kq.prototype.ec;k.V=function(){return this};k.Xn=function(){return this.c};k.Vd=kq.prototype.V;k.qa=function(){return 2};k.Lc=ua;k.U=function(){return this.i};function lq(a){El.call(this);a=a?a:{};this.defaultDataProjection=new Bb({code:"",units:"tile-pixels"});this.b=a.featureClass?a.featureClass:kq;this.a=a.geometryName;this.i=a.layerName?a.layerName:"layer";this.c=a.layers?a.layers:null}v(lq,El);k=lq.prototype;k.U=function(){return"arraybuffer"}; +k.Oa=function(a,b){var c=this.c;a=new Fj.Dd(a);a=new Fj.xf.Bf(a);var d=[],e=this.b,f;for(f in a.layers)if(!c||-1!=c.indexOf(f)){var g=a.layers[f];for(var h=0,l=g.length;hc?~(c<<1):c<<1;b="";d=0;for(c=a.length;d>=5;g+=String.fromCharCode(f+63);b+=g}return b} +function Rq(a,b){b=b?b:1E5;var c=[],d=0,e=0,f;var g=0;for(f=a.length;gh?(c.push(d),e=d=0):e+=5}a=0;for(d=c.length;a>1):e>>1;a=0;for(d=c.length;a=b||"."==b||"-"==b){c.type=4;var b=a.b,d=!1,e=!1;do{if("."==f)d=!0;else if("e"==f||"E"==f)e=!0;var f=a.a.charAt(++a.b)}while("0"<=f&&"9">=f||"."==f&&(void 0===d||!d)||!e&&("e"==f||"E"==f)||e&&("-"==f||"+"==f));a=parseFloat(a.a.substring(b,a.b--));c.value=a}else if("a"<=b&&"z">=b||"A"<=b&&"Z">=b){c.type=1;b=a.b;do f=a.a.charAt(++a.b);while("a"<=f&&"z">= +f||"A"<=f&&"Z">=f);a=a.a.substring(b,a.b--).toUpperCase();c.value=a}else{if(" "==b||"\t"==b||"\r"==b||"\n"==b)return Cr(a);if(""===b)c.type=6;else throw Error("Unexpected character: "+b);}return c}function yr(a){this.i=a;this.a="XY"}function Ar(a){a.b=Cr(a.i)}function Dr(a,b){(b=a.b.type==b)&&Ar(a);return b} +function Br(a){var b=a.b;if(Dr(a,1)){var b=b.value,c="XY",d=a.b;1==a.b.type&&(d=d.value,"Z"===d?c="XYZ":"M"===d?c="XYM":"ZM"===d&&(c="XYZM"),"XY"!==c&&Ar(a));a.a=c;if("GEOMETRYCOLLECTION"==b){a:{if(Dr(a,2)){b=[];do b.push(Br(a));while(Dr(a,5));if(Dr(a,3)){a=b;break a}}else if(Er(a)){a=[];break a}throw Error(Fr(a));}return new tm(a)}d=Gr[b];c=Hr[b];if(!d||!c)throw Error("Invalid geometry type: "+b);b=d.call(a);return new c(b,a.a)}throw Error(Fr(a));}k=yr.prototype; +k.tg=function(){if(Dr(this,2)){var a=Ir(this);if(Dr(this,3))return a}else if(Er(this))return null;throw Error(Fr(this));};k.sg=function(){if(Dr(this,2)){var a=Jr(this);if(Dr(this,3))return a}else if(Er(this))return[];throw Error(Fr(this));};k.ug=function(){if(Dr(this,2)){var a=Kr(this);if(Dr(this,3))return a}else if(Er(this))return[];throw Error(Fr(this));}; +k.fp=function(){if(Dr(this,2)){var a;if(2==this.b.type)for(a=[this.tg()];Dr(this,5);)a.push(this.tg());else a=Jr(this);if(Dr(this,3))return a}else if(Er(this))return[];throw Error(Fr(this));};k.ep=function(){if(Dr(this,2)){var a=Kr(this);if(Dr(this,3))return a}else if(Er(this))return[];throw Error(Fr(this));};k.gp=function(){if(Dr(this,2)){for(var a=[this.ug()];Dr(this,5);)a.push(this.ug());if(Dr(this,3))return a}else if(Er(this))return[];throw Error(Fr(this));}; +function Ir(a){for(var b=[],c=a.a.length,d=0;d=b[0]||a[1]<=b[1]&&a[3]>=b[1]?!0:db(a,this.sb,this)):!1}; +k.ob=function(a){var b=this.a,c=a.slice();c[b]=c[0]+(this.A[b]-this.A[0]);var d;for(d=1;df[2])&&(c=h*Math.ceil((f[0]-c)/h),d=[d[0]+ +c,d[1],d[2]+c,d[3]]);c=this.S[0];f=this.S[1];h=-1;m=Math.pow(this.Jb*g,2);p=[];q=[];g=0;for(l=Fs.length;gga&&(a.Va(b,e),oa=0);ha>ga&&(b.stroke(),ha=0);oa||ha||(b.beginPath(),B=E=NaN);++n;break;case 2:q=z[1];r=m[q];z=m[q+1];A=m[q+2]- +r;q=m[q+3]-z;q=Math.sqrt(A*A+q*q);b.moveTo(r+q,z);b.arc(r,z,q,0,2*Math.PI,!0);++n;break;case 3:b.closePath();++n;break;case 4:q=z[1];r=z[2];var M=z[3];var ba=z[4]*c;var da=z[5]*c;var fb=z[6],ca=z[7],Ub=z[8],uc=z[9];var bc=z[10];A=z[11];L=z[12];var Je=z[13],zg=z[14];for(bc&&(A+=e);qM.width? +M.width-Ub:zg,Bq=fb+uc>M.height?M.height-uc:fb;b.drawImage(M,Ub,uc,rh,Bq,z,bc,rh*c,Bq*c);1!=ca&&(b.globalAlpha=ff);(1!=L||A)&&b.setTransform.apply(b,x)}++n;break;case 5:q=z[1];r=z[2];da=z[3];fb=z[4]*c;ca=z[5]*c;A=z[6];L=z[7]*c;M=z[8];ba=z[9];for((bc=z[10])&&(A+=e);qthis.c&&(this.c=this.i.lineWidth,this.f=null)};function lt(a,b,c,d){bt.call(this,a,b,c,d);this.f=null;this.i={oh:void 0,Md:void 0,Gd:void 0,Hd:null,Id:void 0,Jd:void 0,Kd:void 0,Ld:void 0,fillStyle:void 0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineDashOffset:void 0,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}v(lt,bt); +function mt(a,b,c,d,e){var f=a.i,g=void 0!==f.fillStyle,f=void 0!=f.strokeStyle,h=d.length,l=[1];a.a.push(l);a.b.push(l);for(l=0;lthis.c&&(this.c=c.lineWidth,this.f=null)):(c.strokeStyle=void 0,c.lineCap=void 0,c.lineDash=null,c.lineDashOffset=void 0,c.lineJoin=void 0,c.lineWidth=void 0,c.miterLimit= +void 0)};function nt(a,b){var c=a.i,d=c.fillStyle,e=c.strokeStyle,f=c.lineCap,g=c.lineDash,h=c.lineDashOffset,l=c.lineJoin,m=c.lineWidth,n=c.miterLimit;if(void 0!==d&&("string"!==typeof d||c.oh!=d)){var p=[9,d];"string"!==typeof d&&(b=b.G(),p.push([b[0],b[3]]));a.a.push(p);c.oh=c.fillStyle}void 0===e||c.Md==e&&c.Gd==f&&pa(c.Hd,g)&&c.Id==h&&c.Jd==l&&c.Kd==m&&c.Ld==n||(a.a.push([10,e,m,f,l,n,g,h,!0,1]),c.Md=e,c.Gd=f,c.Hd=g,c.Id=h,c.Jd=l,c.Kd=m,c.Ld=n)};function ot(a,b,c,d){bt.call(this,a,b,c,d);this.C=this.D=this.S=null;this.Ia="";this.o=this.j=0;this.l=void 0;this.u=this.v=0;this.g=this.f=this.i=null}v(ot,bt); +ot.prototype.yc=function(a,b,c,d,e,f){if(""!==this.Ia&&this.g&&(this.i||this.f)){if(this.i){e=this.i;var g=this.S;if(!g||g.fillStyle!=e.fillStyle){var h=[9,e.fillStyle];this.a.push(h);this.b.push(h);g?g.fillStyle=e.fillStyle:this.S={fillStyle:e.fillStyle}}}this.f&&(e=this.f,g=this.D,g&&g.lineCap==e.lineCap&&g.lineDash==e.lineDash&&g.lineDashOffset==e.lineDashOffset&&g.lineJoin==e.lineJoin&&g.lineWidth==e.lineWidth&&g.miterLimit==e.miterLimit&&g.strokeStyle==e.strokeStyle||(h=[10,e.strokeStyle,e.lineWidth, +e.lineCap,e.lineJoin,e.miterLimit,e.lineDash,e.lineDashOffset,!1,1],this.a.push(h),this.b.push(h),g?(g.lineCap=e.lineCap,g.lineDash=e.lineDash,g.lineDashOffset=e.lineDashOffset,g.lineJoin=e.lineJoin,g.lineWidth=e.lineWidth,g.miterLimit=e.miterLimit,g.strokeStyle=e.strokeStyle):this.D={lineCap:e.lineCap,lineDash:e.lineDash,lineDashOffset:e.lineDashOffset,lineJoin:e.lineJoin,lineWidth:e.lineWidth,miterLimit:e.miterLimit,strokeStyle:e.strokeStyle}));e=this.g;g=this.C;g&&g.font==e.font&&g.textAlign== +e.textAlign&&g.textBaseline==e.textBaseline||(h=[11,e.font,e.textAlign,e.textBaseline],this.a.push(h),this.b.push(h),g?(g.font=e.font,g.textAlign=e.textAlign,g.textBaseline=e.textBaseline):this.C={font:e.font,textAlign:e.textAlign,textBaseline:e.textBaseline});dt(this,f);e=this.coordinates.length;a=ct(this,a,b,c,d,!1,!1);a=[5,e,a,this.Ia,this.j,this.o,this.v,this.u,!!this.i,!!this.f,this.l];this.a.push(a);this.b.push(a);gt(this,f)}}; +ot.prototype.Cb=function(a){if(a){var b=a.Fa();b?(b=b.b,b=id(b?b:Sh),this.i?this.i.fillStyle=b:this.i={fillStyle:b}):this.i=null;var c=a.Ga();if(c){var b=c.a,d=c.f,e=c.i,f=c.g,g=c.j,h=c.c,c=c.o,d=void 0!==d?d:"round",e=e?e.slice():Th,f=void 0!==f?f:0,g=void 0!==g?g:"round",h=void 0!==h?h:1,c=void 0!==c?c:10,b=id(b?b:Uh);if(this.f){var l=this.f;l.lineCap=d;l.lineDash=e;l.lineDashOffset=f;l.lineJoin=g;l.lineWidth=h;l.miterLimit=c;l.strokeStyle=b}else this.f={lineCap:d,lineDash:e,lineDashOffset:f,lineJoin:g, +lineWidth:h,miterLimit:c,strokeStyle:b}}else this.f=null;var m=a.a,b=a.i,d=a.c,e=a.o,h=a.f,c=a.b,f=a.Na(),g=a.g,l=a.j;a=void 0!==m?m:"10px sans-serif";g=void 0!==g?g:"center";l=void 0!==l?l:"middle";this.g?(m=this.g,m.font=a,m.textAlign=g,m.textBaseline=l):this.g={font:a,textAlign:g,textBaseline:l};this.Ia=void 0!==f?f:"";this.j=void 0!==b?b:0;this.o=void 0!==d?d:0;this.l=void 0!==e?e:!1;this.v=void 0!==h?h:0;this.u=void 0!==c?c:1}else this.Ia=""};function pt(a,b,c,d,e){this.v=a;this.c=b;this.o=d;this.l=c;this.f=e;this.a={};this.g=jd(1,1);this.j=Bh()}v(pt,ki);var qt={0:[[!0]]};function rt(a,b,c){var d,e=Math.floor(a.length/2);if(b>=e)for(d=e;d=d;)rt(c,a+b,a+d),rt(c,a+d,a+b),rt(c,a-d,a+b),rt(c,a-b,a+d),rt(c,a-b,a-d),rt(c,a-d,a-b),rt(c,a+d,a-b),rt(c,a+b,a-d),d++,e+=1+2*d,0<2*(e-b)+1&&(--b,e+=1-2*b);return qt[a]=c}function tt(a){for(var b in a.a){var c=a.a[b],d;for(d in c)c[d].Te()}} +pt.prototype.Ea=function(a,b,c,d,e,f){d=Math.round(d);var g=2*d+1,h=Kh(this.j,d+.5,d+.5,1/b,-1/b,-c,-a[0],-a[1]),l=this.g;l.canvas.width!==g||l.canvas.height!==g?(l.canvas.width=g,l.canvas.height=g):l.clearRect(0,0,g,g);if(void 0!==this.f){var m=Oa();Pa(m,a);Qa(m,b*(this.f+d),m)}var n=st(d);return ut(this,l,h,c,e,function(a){for(var b=l.getImageData(0,0,g,g).data,c=0;ca.$&&(a.$=d.$),d.daa.ia&&(a.ia=d.ia)):a[b][c]=d:(a[b]={},a[b][c]=d)} +function Ft(a,b,c,d,e,f,g,h,l,m){var n=w(b).toString();n in a.wantedTiles||(a.wantedTiles[n]={});var p=a.wantedTiles[n];a=a.tileQueue;var q=c.minZoom,r,u,x;for(x=g;x>=q;--x){var B=oc(c,f,x,B);var E=c.Da(x);for(r=B.ca;r<=B.$;++r)for(u=B.da;u<=B.ia;++u)if(g-x<=h){var A=b.Nc(x,r,u,d,e);0==A.getState()&&(p[A.bb()]=!0,A.bb()in a.a||a.f([A,n,tc(c,A.ta),E]));l&&l.call(m,A)}else b.Ug(x,r,u,e)}};function Gt(a){xt.call(this,a);this.fa=Bh()}v(Gt,xt);function Ht(a,b,c){var d=b.pixelRatio,e=b.size[0]*d,f=b.size[1]*d,g=b.viewState.rotation,h=ib(c),l=hb(c),m=gb(c);c=eb(c);Gh(b.coordinateToPixelTransform,h);Gh(b.coordinateToPixelTransform,l);Gh(b.coordinateToPixelTransform,m);Gh(b.coordinateToPixelTransform,c);a.save();Vh(a,-g,e/2,f/2);a.beginPath();a.moveTo(h[0]*d,h[1]*d);a.lineTo(l[0]*d,l[1]*d);a.lineTo(m[0]*d,m[1]*d);a.lineTo(c[0]*d,c[1]*d);a.clip();Vh(a,g,e/2,f/2)} +function It(a,b,c,d,e){var f=a.a;if(Rc(f,b)){var g=d.size[0]*d.pixelRatio,h=d.size[1]*d.pixelRatio,l=d.viewState.rotation;Vh(c,-l,g/2,h/2);a=e?e:Jt(a,d,0);f.b(new Rh(b,new Xh(c,d.pixelRatio,d.extent,a,d.viewState.rotation),d,c,null));Vh(c,l,g/2,h/2)}}Gt.prototype.u=function(a,b,c,d){if(this.Ea(a,b,0,mf,this))return c.call(d,this.a,null)};Gt.prototype.ef=function(a,b,c,d){It(this,"postcompose",a,b,d)}; +function Jt(a,b,c){var d=b.viewState,e=b.pixelRatio,f=e/d.resolution;return Kh(a.fa,e*b.size[0]/2,e*b.size[1]/2,f,-f,-d.rotation,-d.center[0]+c,-d.center[1])};function Kt(a,b){return w(a)-w(b)}function Lt(a,b){a=.5*a/b;return a*a}function Mt(a,b,c,d,e,f){var g=!1,h;if(h=c.Y()){var l=h.Ye();2==l||3==l?h.Bj(e,f):(0==l&&h.load(),h.Nh(e,f),g=!0)}if(e=(0,c.Za)(b))d=e.Vd(d),(0,Nt[d.U()])(a,d,c,b);return g} +var Nt={Point:function(a,b,c,d){var e=c.Y();if(e){if(2!=e.Ye())return;var f=a.b(c.Ba(),"Image");f.Ub(e);f.qc(b,d)}if(e=c.Na())a=a.b(c.Ba(),"Text"),a.Cb(e),a.yc(b.ga(),0,2,2,b,d)},LineString:function(a,b,c,d){var e=c.Ga();if(e){var f=a.b(c.Ba(),"LineString");f.Ma(null,e);f.mc(b,d)}if(e=c.Na())a=a.b(c.Ba(),"Text"),a.Cb(e),a.yc(di(b),0,2,2,b,d)},Polygon:function(a,b,c,d){var e=c.Fa(),f=c.Ga();if(e||f){var g=a.b(c.Ba(),"Polygon");g.Ma(e,f);g.rc(b,d)}if(e=c.Na())a=a.b(c.Ba(),"Text"),a.Cb(e),a.yc(Wf(b), +0,2,2,b,d)},MultiPoint:function(a,b,c,d){var e=c.Y();if(e){if(2!=e.Ye())return;var f=a.b(c.Ba(),"Image");f.Ub(e);f.oc(b,d)}if(e=c.Na())a=a.b(c.Ba(),"Text"),a.Cb(e),c=b.ga(),a.yc(c,0,c.length,b.qa(),b,d)},MultiLineString:function(a,b,c,d){var e=c.Ga();if(e){var f=a.b(c.Ba(),"LineString");f.Ma(null,e);f.nc(b,d)}if(e=c.Na())a=a.b(c.Ba(),"Text"),a.Cb(e),c=ei(b),a.yc(c,0,c.length,2,b,d)},MultiPolygon:function(a,b,c,d){var e=c.Fa(),f=c.Ga();if(f||e){var g=a.b(c.Ba(),"Polygon");g.Ma(e,f);g.pc(b,d)}if(e= +c.Na())a=a.b(c.Ba(),"Text"),a.Cb(e),c=gi(b),a.yc(c,0,c.length,2,b,d)},GeometryCollection:function(a,b,c,d){b=b.a;var e;var f=0;for(e=b.length;fl[2];)++L,n=m*L,n=Jt(this,a,n),p.La(x,e,n,g,f),h-=m;n=Jt(this,a,0)}Vh(x,g,E/2,A/2);x!=c&&(It(this,"render",x,a,n),c.drawImage(x.canvas,-r,-u),x.translate(-r,-u));x.globalAlpha=B}q&&c.restore();this.ef(c,a,b,n)}; +Ot.prototype.Ea=function(a,b,c,d,e){if(this.f){var f=this.a,g={};return this.f.Ea(a,b.viewState.resolution,b.viewState.rotation,c,{},function(a){var b=w(a).toString();if(!(b in g))return g[b]=!0,d.call(e,a,f)})}};Ot.prototype.D=function(){zt(this)}; +Ot.prototype.sd=function(a){function b(a){var b=a.Lc();if(b)var d=b.call(a,m);else(b=c.f)&&(d=b(a,m));if(d){if(d){b=!1;if(Array.isArray(d))for(var e=0,f=d.length;ea.ad:e<=a.ad}a.l?(e=b.coordinate,c=a.j.V(),a.g===pu?d=a.a:a.g===ou?(d=a.a[0],d=d[d.length-1],wu(a,b)&&(e=a.l.slice())):(d=a.a,d=d[d.length-1]),d[0]=e[0],d[1]=e[1],a.Za(a.a,c),a.B&&a.B.V().ma(e),c instanceof D&&a.g!==ou?(a.C||(a.C=new H(new O(null))),e=c.Ch(0),b=a.C.V(),b.ba(e.ja,e.ga())):a.I&&(b=a.C.V(),b.ma(a.I)),yu(a)):(b=b.coordinate.slice(),a.B?a.B.V().ma(b):(a.B=new H(new C(b)), +yu(a)));return!0}function wu(a,b){var c=!1;if(a.j){var d=!1,e=[a.l];a.g===qu?d=a.a.length>a.Sa:a.g===ou&&(d=a.a[0].length>a.Sa,e=[a.a[0][0],a.a[0][a.a[0].length-2]]);if(d)for(var d=b.map,f=0,g=e.length;f=a.va&&(a.u?e.pop():d=!0);e.push(b.slice());a.Za(e,c)}else a.g===ou&&(e=a.a[0],e.length>=a.va&&(a.u?e.pop():d=!0),e.push(b.slice()),d&&(a.l=e[0]),a.Za(a.a,c));yu(a);d&&a.Pd()} +k.Op=function(){if(this.j){var a=this.j.V();if(this.g===qu){var b=this.a;b.splice(-2,1);this.Za(b,a);2<=b.length&&(this.l=b[b.length-2].slice())}else if(this.g===ou){b=this.a[0];b.splice(-2,1);var c=this.C.V();c.ma(b);this.Za(this.a,a)}0===b.length&&(this.l=null);yu(this)}}; +k.Pd=function(){var a=xu(this),b=this.a,c=a.V();this.g===qu?(b.pop(),this.Za(b,c)):this.g===ou&&(b[0].pop(),this.Za(b,c),b=c.X());"MultiPoint"===this.R?a.Ra(new Q([b])):"MultiLineString"===this.R?a.Ra(new P([b])):"MultiPolygon"===this.R&&a.Ra(new R([b]));this.b(new zu("drawend",a));this.$a&&this.$a.push(a);this.Yb&&this.Yb.yb(a)};function xu(a){a.l=null;var b=a.j;b&&(a.j=null,a.B=null,a.C=null,a.pa.ha().clear(!0));return b} +k.vn=function(a){var b=a.V();this.j=a;this.a=b.X();a=this.a[this.a.length-1];this.l=a.slice();this.a.push(a.slice());yu(this);this.b(new zu("drawstart",this.j))};k.Xc=nf;function yu(a){var b=[];a.j&&b.push(a.j);a.C&&b.push(a.C);a.B&&b.push(a.B);a=a.pa.ha();a.clear(!0);a.cd(b)}k.ri=function(){var a=this.v,b=this.c();a&&b||xu(this);this.pa.setMap(b?a:null)}; +function nu(a){var b;"Point"===a||"MultiPoint"===a?b=pu:"LineString"===a||"MultiLineString"===a?b=qu:"Polygon"===a||"MultiPolygon"===a?b=ou:"Circle"===a&&(b=vu);return b}var pu="Point",qu="LineString",ou="Polygon",vu="Circle";function zu(a,b){Oc.call(this,a);this.feature=b}v(zu,Oc);function Au(a){this.a=this.j=null;this.C=!1;this.B=this.l=null;a||(a={});a.extent&&this.g(a.extent);Dg.call(this,{handleDownEvent:Bu,handleDragEvent:Cu,handleEvent:Du,handleUpEvent:Eu});this.u=new T({source:new U({useSpatialIndex:!1,wrapX:!!a.wrapX}),style:a.boxStyle?a.boxStyle:Fu(),updateWhileAnimating:!0,updateWhileInteracting:!0});this.I=new T({source:new U({useSpatialIndex:!1,wrapX:!!a.wrapX}),style:a.pointerStyle?a.pointerStyle:Gu(),updateWhileAnimating:!0,updateWhileInteracting:!0})}v(Au,Dg); +function Du(a){if(!(a instanceof ee))return!0;if("pointermove"==a.type&&!this.D){var b=a.pixel,c=a.map,d=Hu(this,b,c);d||(d=c.Wa(b));Iu(this,d)}Eg.call(this,a);return!1} +function Bu(a){function b(a){var b=null,c=null;a[0]==e[0]?b=e[2]:a[0]==e[2]&&(b=e[0]);a[1]==e[1]?c=e[3]:a[1]==e[3]&&(c=e[1]);return null!==b&&null!==c?[b,c]:null}var c=a.pixel,d=a.map,e=this.G();(a=Hu(this,c,d))&&e?(c=a[0]==e[0]||a[0]==e[2]?a[0]:null,d=a[1]==e[1]||a[1]==e[3]?a[1]:null,null!==c&&null!==d?this.a=Ju(b(a)):null!==c?this.a=Ku(b([c,e[1]]),b([c,e[3]])):null!==d&&(this.a=Ku(b([e[0],d]),b([e[2],d])))):(a=d.Wa(c),this.g([a[0],a[1],a[0],a[1]]),this.a=Ju(a));return!0} +function Cu(a){this.a&&(a=a.coordinate,this.g(this.a(a)),Iu(this,a));return!0}function Eu(){this.a=null;var a=this.G();a&&jb(a)||this.g(null);return!1}function Fu(){var a=gl();return function(){return a.Polygon}}function Gu(){var a=gl();return function(){return a.Point}}function Ju(a){return function(b){return Na([a,b])}}function Ku(a,b){return a[0]==b[0]?function(c){return Na([a,[c[0],b[1]]])}:a[1]==b[1]?function(c){return Na([a,[b[0],c[1]]])}:null} +function Hu(a,b,c){function d(a,b){return kf(e,a)-kf(e,b)}var e=c.Wa(b),f=a.G();if(f){f=[[[f[0],f[1]],[f[0],f[3]]],[[f[0],f[3]],[f[2],f[3]]],[[f[2],f[3]],[f[2],f[1]]],[[f[2],f[1]],[f[0],f[1]]]];f.sort(d);var f=f[0],g=af(e,f),h=c.Ja(g);if(10>=jf(b,h))return b=c.Ja(f[0]),c=c.Ja(f[1]),b=hf(h,b),c=hf(h,c),a.C=10>=Math.sqrt(Math.min(b,c)),a.C&&(g=b>c?f[1]:f[0]),g}return null}function Iu(a,b){var c=a.B;c?c.V().ma(b):(c=new H(new C(b)),a.B=c,a.I.ha().yb(c))} +Au.prototype.setMap=function(a){this.u.setMap(a);this.I.setMap(a);Dg.prototype.setMap.call(this,a)};Au.prototype.G=function(){return this.j};Au.prototype.g=function(a){this.j=a?a:null;var b=this.l;b?a?b.Ra(Yf(a)):b.Ra(void 0):(this.l=b=a?new H(Yf(a)):new H({}),this.u.ha().yb(b));this.b(new Lu(this.j))};function Lu(a){Oc.call(this,Mu);this.b=a}v(Lu,Oc);var Mu="extentchanged";function Nu(a){Dg.call(this,{handleDownEvent:Ou,handleDragEvent:Pu,handleEvent:Qu,handleUpEvent:Ru});this.ad=a.condition?a.condition:Cg;this.$a=function(a){return xg(a)&&wg(a)};this.xb=a.deleteCondition?a.deleteCondition:this.$a;this.Yb=a.insertVertexCondition?a.insertVertexCondition:mf;this.Sa=this.g=null;this.va=[0,0];this.C=this.I=!1;this.a=new Gj;this.fa=void 0!==a.pixelTolerance?a.pixelTolerance:10;this.l=this.pa=!1;this.j=[];this.B=new T({source:new U({useSpatialIndex:!1,wrapX:!!a.wrapX}),style:a.style? +a.style:Su(),updateWhileAnimating:!0,updateWhileInteracting:!0});this.T={Point:this.Dn,LineString:this.ti,LinearRing:this.ti,Polygon:this.En,MultiPoint:this.Bn,MultiLineString:this.An,MultiPolygon:this.Cn,Circle:this.yn,GeometryCollection:this.zn};this.u=a.features;this.u.forEach(this.kg,this);y(this.u,"add",this.wn,this);y(this.u,"remove",this.xn,this);this.R=null}v(Nu,Dg);k=Nu.prototype; +k.kg=function(a){var b=a.V();b&&b.U()in this.T&&this.T[b.U()].call(this,a,b);(b=this.v)&&b.c&&this.c()&&Tu(this,this.va,b);y(a,"change",this.si,this)};function Uu(a,b){a.C||(a.C=!0,a.b(new Vu("modifystart",a.u,b)))}function Wu(a,b){Xu(a,b);a.g&&!a.u.dc()&&(a.B.ha().Gb(a.g),a.g=null);Kc(b,"change",a.si,a)}function Xu(a,b){a=a.a;var c=[];a.forEach(function(a){b===a.feature&&c.push(a)});for(var d=c.length-1;0<=d;--d)a.remove(c[d])} +k.Ha=function(a){this.g&&!a&&(this.B.ha().Gb(this.g),this.g=null);Dg.prototype.Ha.call(this,a)};k.setMap=function(a){this.B.setMap(a);Dg.prototype.setMap.call(this,a)};k.wn=function(a){this.kg(a.element)};k.si=function(a){this.l||(a=a.target,Wu(this,a),this.kg(a))};k.xn=function(a){Wu(this,a.element)};k.Dn=function(a,b){var c=b.X();a={feature:a,geometry:b,la:[c,c]};this.a.Ca(b.G(),a)}; +k.Bn=function(a,b){var c=b.X(),d;var e=0;for(d=c.length;em?h[1]:h[0]),Yu(a,l),m=1,c=f.length;mn&&(n=0);f=g.geometry;var p=d=f.X();var q=!1;switch(f.U()){case "MultiLineString":2c&&(a.index+=e)})}function Su(){var a=gl();return function(){return a.Point}}function Vu(a,b,c){Oc.call(this,a);this.features=b;this.mapBrowserEvent=c}v(Vu,Oc);function cv(a){ng.call(this,{handleEvent:dv});a=a?a:{};this.C=a.condition?a.condition:wg;this.D=a.addCondition?a.addCondition:nf;this.B=a.removeCondition?a.removeCondition:nf;this.I=a.toggleCondition?a.toggleCondition:yg;this.l=a.multi?a.multi:!1;this.o=a.filter?a.filter:mf;this.j=a.hitTolerance?a.hitTolerance:0;this.g=new T({source:new U({useSpatialIndex:!1,features:a.features,wrapX:a.wrapX}),style:a.style?a.style:ev(),updateWhileAnimating:!0,updateWhileInteracting:!0});if(a.layers)if("function"=== +typeof a.layers)a=a.layers;else{var b=a.layers;a=function(a){return ja(b,a)}}else a=mf;this.u=a;this.a={};a=this.g.ha().f;y(a,"add",this.Fn,this);y(a,"remove",this.Jn,this)}v(cv,ng);k=cv.prototype;k.Gn=function(){return this.g.ha().f};k.Hn=function(){return this.j};k.In=function(a){a=w(a);return this.a[a]}; +function dv(a){if(!this.C(a))return!0;var b=this.D(a),c=this.B(a),d=this.I(a),e=!b&&!c&&!d,f=a.map,g=this.g.ha().f,h=[],l=[];if(e){ub(this.a);f.we(a.pixel,function(a,b){if(this.o(a,b))return l.push(a),a=w(a),this.a[a]=b,!this.l}.bind(this),{layerFilter:this.u,hitTolerance:this.j});for(e=g.dc()-1;0<=e;--e){var f=g.item(e),m=l.indexOf(f);-1b?m[1]:m[0],l=d.Ja(f)}else a.C&&(f=h?$e(c,g[0].feature.V()):af(c,m),l=d.Ja(f),jf(b,l)<=a.g&&(e=!0,a.R&&!h&&(c= +d.Ja(m[0]),h=d.Ja(m[1]),c=hf(l,c),b=hf(l,h),h=Math.sqrt(Math.min(c,b)),h=h<=a.g)))&&(f=c>b?m[1]:m[0],l=d.Ja(f));e&&(l=[Math.round(l[0]),Math.round(l[1])])}return{nq:e,vertex:f,wq:l}}k.Dj=function(a){this.Gb(a,!1);this.yb(a,!1)};k.Mn=function(a,b){b=Zf(b).X()[0];var c;var d=0;for(c=b.length-1;dca&&(ca=uc,m=Ub)}if(!ca){g=null;break a}ca=g[m];g[m]=g[l];g[l]=ca;for(m=l+1;mthis.b/2){var b=[[a.source[0][0],a.source[0][1]],[a.source[1][0],a.source[1][1]],[a.source[2][0],a.source[2][1]]];b[0][0]-n>this.b/2&&(b[0][0]-=this.b);b[1][0]-n>this.b/2&&(b[1][0]-=this.b);b[2][0]-n>this.b/2&&(b[2][0]-=this.b);Math.max(b[0][0],b[1][0],b[2][0])-Math.min(b[0][0],b[1][0],b[2][0])p,u=!1;if(0a.v),u)){Math.abs(b[0]-d[0])<=Math.abs(b[1]-d[1])?(r=[(c[0]+d[0])/2,(c[1]+d[1])/2],q=a.a(r),n=[(e[0]+b[0])/2,(e[1]+b[1])/2],p=a.a(n),Ev(a,b,c,r,n,f,g,q,p,m-1),Ev(a,n,r,d,e,p,q,h,l,m-1)):(r=[(b[0]+c[0])/2,(b[1]+c[1])/2],q=a.a(r),n=[(d[0]+e[0])/2,(d[1]+e[1])/2],p=a.a(n),Ev(a,b,r,n,e,f,q,p,l,m-1),Ev(a,r,c,d,n,q,g,h,p,m-1));return}if(r){if(!a.l)return;a.o=!0}a.c.push({source:[f,h,l],target:[b,d,e]});a.c.push({source:[f,g,h],target:[b,c,d]})}} +function Fv(a){var b=Oa();a.c.forEach(function(a){a=a.source;Pa(b,a[0]);Pa(b,a[1]);Pa(b,a[2])});return b};function Gv(a,b,c,d,e,f){this.v=b;this.l=a.G();var g=b.G(),h=g?pb(c,g):c,g=Av(a,b,nb(h),d);this.j=new Dv(a,b,h,this.l,.5*g);this.c=d;this.i=c;a=Fv(this.j);this.o=(this.Hb=f(a,g,e))?this.Hb.a:1;this.ee=this.g=null;e=2;f=[];this.Hb&&(e=0,f=this.Hb.f);Is.call(this,c,d,this.o,e,f)}v(Gv,Is);Gv.prototype.ka=function(){1==this.state&&(Ec(this.ee),this.ee=null);Is.prototype.ka.call(this)};Gv.prototype.Y=function(){return this.g}; +Gv.prototype.de=function(){var a=this.Hb.getState();2==a&&(this.g=Cv(lb(this.i)/this.c,mb(this.i)/this.c,this.o,this.Hb.resolution,0,this.c,this.i,this.j,[{extent:this.Hb.G(),image:this.Hb.Y()}],0));this.state=a;this.s()};Gv.prototype.load=function(){if(0==this.state){this.state=1;this.s();var a=this.Hb.getState();2==a||3==a?this.de():(this.ee=y(this.Hb,"change",function(){var a=this.Hb.getState();if(2==a||3==a)Ec(this.ee),this.ee=null,this.de()},this),this.Hb.load())}};function Hv(a){$t.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,state:a.state});this.C=void 0!==a.resolutions?a.resolutions:null;this.a=null;this.fa=0}v(Hv,$t);function Iv(a,b){a.C&&(b=a.C[ka(a.C,b,0)]);return b} +Hv.prototype.Y=function(a,b,c,d){var e=this.c;if(e&&d&&!dc(e,d)){if(this.a){if(this.fa==this.i&&dc(this.a.v,d)&&this.a.resolution==b&&this.a.a==c&&bb(this.a.G(),a))return this.a;Nc(this.a);this.a=null}this.a=new Gv(e,d,a,b,c,function(a,b,c){return this.Jc(a,b,c,e)}.bind(this));this.fa=this.i;return this.a}e&&(d=e);return this.Jc(a,b,c,d)};Hv.prototype.o=function(a){a=a.target;switch(a.getState()){case 1:this.b(new Jv(Kv,a));break;case 2:this.b(new Jv(Lv,a));break;case 3:this.b(new Jv(Mv,a))}}; +function Nv(a,b){a.Y().src=b}function Jv(a,b){Oc.call(this,a);this.image=b}v(Jv,Oc);var Kv="imageloadstart",Lv="imageloadend",Mv="imageloaderror";function Ov(a){Hv.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions,state:a.state});this.pa=a.canvasFunction;this.R=null;this.T=0;this.va=void 0!==a.ratio?a.ratio:1.5}v(Ov,Hv);Ov.prototype.Jc=function(a,b,c,d){b=Iv(this,b);var e=this.R;if(e&&this.T==this.i&&e.resolution==b&&e.a==c&&Va(e.G(),a))return e;a=a.slice();rb(a,this.va);(d=this.pa(a,b,c,[lb(a)/b*c,mb(a)/b*c],d))&&(e=new Ks(a,b,c,this.j,d));this.R=e;this.T=this.i;return e};function Pv(a){this.f=a.source;this.$a=Bh();this.g=jd();this.l=[0,0];this.Sa=void 0==a.renderBuffer?100:a.renderBuffer;this.B=null;Ov.call(this,{attributions:a.attributions,canvasFunction:this.tk.bind(this),logo:a.logo,projection:a.projection,ratio:a.ratio,resolutions:a.resolutions,state:this.f.getState()});this.I=null;this.v=void 0;this.Ii(a.style);y(this.f,"change",this.ro,this)}v(Pv,Ov);k=Pv.prototype; +k.tk=function(a,b,c,d,e){var f=new pt(.5*b/c,a,b,this.f.T,this.Sa);this.f.Yd(a,b,e);var g=!1;this.f.$b(a,function(a){var d;if(!(d=g)){var e;(d=a.Lc())?e=d.call(a,b):this.v&&(e=this.v(a,b));if(e){var h,p=!1;Array.isArray(e)||(e=[e]);d=0;for(h=e.length;da[0]||a[0]>e[0]||0>a[1]||a[1]>e[1])&&(this.f|| +(this.f=jd(1,1)),this.f.clearRect(0,0,1,1),this.f.drawImage(this.M.Y(),a[0],a[1],1,1,0,0,1,1),e=this.f.getImageData(0,0,1,1).data,0=d)this.state=4;else if(this.l=new Dv(a,c,f,e,d*(void 0!==m?m:.5)),this.l.c.length)if(this.g=b.tc(d),c=Fv(this.l),e&&(a.i?(c[1]=Ca(c[1],e[1],e[3]),c[3]=Ca(c[3],e[1],e[3])):c=pb(c,e)),jb(c)){a= +oc(b,c,this.g);for(b=a.ca;b<=a.$;b++)for(c=a.da;c<=a.ia;c++)(m=l(this.g,b,c,g))&&this.a.push(m);this.a.length||(this.state=4)}else this.state=4;else this.state=4;else this.state=4}v(hw,Ls);hw.prototype.ka=function(){1==this.state&&(this.yd.forEach(Ec),this.yd=null);Ls.prototype.ka.call(this)};hw.prototype.Y=function(){return this.v}; +hw.prototype.de=function(){var a=[];this.a.forEach(function(b){b&&2==b.getState()&&a.push({extent:this.c.Aa(b.ta),image:b.Y()})},this);this.a.length=0;if(a.length){var b=this.o[0],c=this.j.gb(b),d="number"===typeof c?c:c[0],c="number"===typeof c?c:c[1],b=this.j.Da(b),e=this.c.Da(this.g),f=this.j.Aa(this.o);this.v=Cv(d,c,this.S,e,this.c.G(),b,f,this.l,a,this.u,this.D);this.state=2}else this.state=3;this.s()}; +hw.prototype.load=function(){if(0==this.state){this.state=1;this.s();var a=0;this.yd=[];this.a.forEach(function(b){var c=b.getState();if(0==c||1==c){a++;var d=y(b,"change",function(){var c=b.getState();if(2==c||3==c||4==c)Ec(d),a--,a||(this.yd.forEach(Ec),this.yd=null,this.de())},this);this.yd.push(d)}},this);this.a.forEach(function(a){0==a.getState()&&a.load()});a||setTimeout(this.de.bind(this),0)}};function iw(a,b){var c=/\{z\}/g,d=/\{x\}/g,e=/\{y\}/g,f=/\{-y\}/g;return function(g){if(g)return a.replace(c,g[0].toString()).replace(d,g[1].toString()).replace(e,function(){return(-g[2]-1).toString()}).replace(f,function(){var a=b.a?b.a[g[0]]:null;xa(a,55);return(a.ia-a.da+1+g[2]).toString()})}}function jw(a,b){for(var c=a.length,d=Array(c),e=0;ea.highWaterMark}nw.prototype.fd=function(a){for(var b,c;ow(this);){b=this.a.Yc;c=b.ta[0].toString();var d;if(d=c in a)b=b.ta,d=za(a[c],b[1],b[2]);if(d)break;else Nc(this.pop())}};function pw(a){$t.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,state:a.state,wrapX:a.wrapX});this.va=void 0!==a.opaque?a.opaque:!1;this.$a=void 0!==a.tilePixelRatio?a.tilePixelRatio:1;this.tileGrid=void 0!==a.tileGrid?a.tileGrid:null;this.a=new nw(a.cacheSize);this.o=[0,0];this.uc=""}v(pw,$t);k=pw.prototype;k.Ki=function(){return ow(this.a)};k.fd=function(a,b){(a=this.Wd(a))&&a.fd(b)}; +function yt(a,b,c,d,e){b=a.Wd(b);if(!b)return!1;for(var f=!0,g,h,l=d.ca;l<=d.$;++l)for(var m=d.da;m<=d.ia;++m)g=a.Sb(c,l,m),h=!1,b.b.hasOwnProperty(g)&&(g=b.get(g),(h=2===g.getState())&&(h=!1!==e(g))),h||(f=!1);return f}k.Wf=function(){return 0};function qw(a,b){a.uc!==b&&(a.uc=b,a.s())}k.Sb=function(a,b,c){return a+"/"+b+"/"+c};k.Zf=function(){return this.va};k.ab=function(){return this.tileGrid};k.Ta=function(a){return this.tileGrid?this.tileGrid:vc(a)}; +k.Wd=function(a){var b=this.c;return b&&!dc(b,a)?null:this.a};k.nb=function(){return this.$a};k.Xd=function(a,b,c){c=this.Ta(c);b=this.nb(b);a=Ma(c.gb(a),this.o);return 1==b?a:La(a,b,this.o)};function rw(a,b,c){var d=void 0!==c?c:a.c;c=a.Ta(d);if(a.u&&d.c){var e=b;b=e[0];a=tc(c,e);d=zc(d);Ta(d,a)?b=e:(e=lb(d),a[0]+=e*Math.ceil((d[0]-a[0])/e),b=c.bg(a,b))}e=b[0];d=b[1];a=b[2];if(c.minZoom>e||e>c.maxZoom)c=!1;else{var f=c.G();c=(c=f?oc(c,f,e):c.a?c.a[e]:null)?za(c,d,a):!0}return c?b:null} +k.sa=function(){this.a.clear();this.s()};k.Ug=ua;function sw(a,b){Oc.call(this,a);this.tile=b}v(sw,Oc);function tw(a){pw.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,extent:a.extent,logo:a.logo,opaque:a.opaque,projection:a.projection,state:a.state,tileGrid:a.tileGrid,tilePixelRatio:a.tilePixelRatio,wrapX:a.wrapX});this.tileLoadFunction=a.tileLoadFunction;this.tileUrlFunction=this.Fc?this.Fc.bind(this):lw;this.urls=null;a.urls?this.eb(a.urls):a.url&&this.jb(a.url);a.tileUrlFunction&&this.cb(a.tileUrlFunction)}v(tw,pw);k=tw.prototype;k.pb=function(){return this.tileLoadFunction}; +k.qb=function(){return this.tileUrlFunction};k.rb=function(){return this.urls};k.Li=function(a){a=a.target;switch(a.getState()){case 1:this.b(new sw("tileloadstart",a));break;case 2:this.b(new sw("tileloadend",a));break;case 3:this.b(new sw("tileloaderror",a))}};k.vb=function(a){this.a.clear();this.tileLoadFunction=a;this.s()};k.cb=function(a,b){this.tileUrlFunction=a;"undefined"!==typeof b?qw(this,b):this.s()}; +k.jb=function(a){var b=this.urls=mw(a);this.cb(this.Fc?this.Fc.bind(this):jw(b,this.tileGrid),a)};k.eb=function(a){this.urls=a;var b=a.join("\n");this.cb(this.Fc?this.Fc.bind(this):jw(a,this.tileGrid),b)};k.Ug=function(a,b,c){a=this.Sb(a,b,c);this.a.b.hasOwnProperty(a)&&this.a.get(a)};function X(a){tw.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,extent:a.extent,logo:a.logo,opaque:a.opaque,projection:a.projection,state:a.state,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction?a.tileLoadFunction:uw,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:a.tileUrlFunction,url:a.url,urls:a.urls,wrapX:a.wrapX});this.crossOrigin=void 0!==a.crossOrigin?a.crossOrigin:null;this.tileClass=a.tileClass?a.tileClass:Os;this.g={};this.v={};this.Sa=a.reprojectionErrorThreshold;this.I= +!1}v(X,tw);k=X.prototype;k.Ki=function(){if(ow(this.a))return!0;for(var a in this.g)if(ow(this.g[a]))return!0;return!1};k.fd=function(a,b){a=this.Wd(a);this.a.fd(this.a==a?b:{});for(var c in this.g){var d=this.g[c];d.fd(d==a?b:{})}};k.Wf=function(a){return this.c&&a&&!dc(this.c,a)?0:this.Xf()};k.Xf=function(){return 0};k.Zf=function(a){return this.c&&a&&!dc(this.c,a)?!1:tw.prototype.Zf.call(this,a)}; +k.Ta=function(a){var b=this.c;return!this.tileGrid||b&&!dc(b,a)?(b=w(a).toString(),b in this.v||(this.v[b]=vc(a)),this.v[b]):this.tileGrid};k.Wd=function(a){var b=this.c;if(!b||dc(b,a))return this.a;a=w(a).toString();a in this.g||(this.g[a]=new nw(this.a.highWaterMark));return this.g[a]};function vw(a,b,c,d,e,f,g){b=[b,c,d];e=(c=rw(a,b,f))?a.tileUrlFunction(c,e,f):void 0;e=new a.tileClass(b,void 0!==e?0:4,void 0!==e?e:"",a.crossOrigin,a.tileLoadFunction);e.key=g;y(e,"change",a.Li,a);return e} +k.Nc=function(a,b,c,d,e){if(this.c&&e&&!dc(this.c,e)){var f=this.Wd(e);c=[a,b,c];var g;a=this.Sb.apply(this,c);f.b.hasOwnProperty(a)&&(g=f.get(a));b=this.uc;if(g&&g.key==b)return g;var h=this.c,l=this.Ta(h),m=this.Ta(e),n=rw(this,c,e);d=new hw(h,l,e,m,c,n,this.nb(d),this.Xf(),function(a,b,c,d){return ww(this,a,b,c,d,h)}.bind(this),this.Sa,this.I);d.key=b;g?(d.i=g,f.replace(a,d)):f.set(a,d);return d}return ww(this,a,b,c,d,e)}; +function ww(a,b,c,d,e,f){var g=a.Sb(b,c,d),h=a.uc;if(a.a.b.hasOwnProperty(g)){var l=a.a.get(g);if(l.key!=h){var m=l;l=vw(a,b,c,d,e,f,h);0==m.getState()?l.i=m.i:l.i=m;if(l.i){b=l.i;c=l;do{if(2==b.getState()){b.i=null;break}else 1==b.getState()?c=b:0==b.getState()?c.i=b.i:c=b;b=c.i}while(b)}a.a.replace(g,l)}}else l=vw(a,b,c,d,e,f,h),a.a.set(g,l);return l}k.Pb=function(a){if(this.I!=a){this.I=a;for(var b in this.g)this.g[b].clear();this.s()}}; +k.Qb=function(a,b){if(a=Tb(a))a=w(a).toString(),a in this.v||(this.v[a]=b)};function uw(a,b){a.Y().src=b};function xw(a){this.B=void 0!==a.hidpi?a.hidpi:!1;X.call(this,{cacheSize:a.cacheSize,crossOrigin:"anonymous",opaque:!0,projection:Tb("EPSG:3857"),reprojectionErrorThreshold:a.reprojectionErrorThreshold,state:"loading",tileLoadFunction:a.tileLoadFunction,tilePixelRatio:this.B?2:1,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.R=void 0!==a.culture?a.culture:"en-us";this.C=void 0!==a.maxZoom?a.maxZoom:-1;this.f=a.key;this.l=a.imagerySet;gw("https://dev.virtualearth.net/REST/v1/Imagery/Metadata/"+this.l+"?uriScheme=https&include=ImageryProviders&key="+ +this.f,this.pa.bind(this),void 0,"jsonp")}v(xw,X);var yw=new Ac({html:'Terms of Use'});xw.prototype.T=function(){return this.f};xw.prototype.fa=function(){return this.l}; +xw.prototype.pa=function(a){if(200!=a.statusCode||"OK"!=a.statusDescription||"ValidCredentials"!=a.authenticationResultCode||1!=a.resourceSets.length||1!=a.resourceSets[0].resources.length)bu(this,"error");else{var b=a.brandLogoUri;-1==b.indexOf("https")&&(b=b.replace("http","https"));var c=a.resourceSets[0].resources[0],d=-1==this.C?c.zoomMax:this.C;a=zc(this.c);var e=xc({extent:a,minZoom:c.zoomMin,maxZoom:d,tileSize:(c.imageWidth==c.imageHeight?c.imageWidth:[c.imageWidth,c.imageHeight])/this.nb()}); +this.tileGrid=e;var f=this.R,g=this.B;this.tileUrlFunction=kw(c.imageUrlSubdomains.map(function(a){var b=[0,0,0],d=c.imageUrl.replace("{subdomain}",a).replace("{culture}",f);return function(a){if(a)return jc(a[0],a[1],-a[2]-1,b),a=d,g&&(a+="&dpi=d1&device=mobile"),a.replace("{quadkey}",kc(b))}}));if(c.imageryProviders){var h=Vb(Tb("EPSG:4326"),this.c);a=c.imageryProviders.map(function(a){var b=a.attribution,c={};a.coverageAreas.forEach(function(a){var b=a.zoomMin,f=Math.min(a.zoomMax,d);a=a.bbox; +a=sb([a[1],a[0],a[3],a[2]],h);var g;for(g=b;g<=f;++g){var l=g.toString();b=oc(e,a,g);l in c?c[l].push(b):c[l]=[b]}});return new Ac({html:b,tileRanges:c})});a.push(yw);this.ua(a)}this.D=b;bu(this,"ready")}};function zw(a){a=a||{};var b=void 0!==a.projection?a.projection:"EPSG:3857",c=void 0!==a.tileGrid?a.tileGrid:xc({extent:zc(b),maxZoom:a.maxZoom,minZoom:a.minZoom,tileSize:a.tileSize});X.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,opaque:a.opaque,projection:b,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:c,tileLoadFunction:a.tileLoadFunction,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:a.tileUrlFunction,url:a.url,urls:a.urls, +wrapX:void 0!==a.wrapX?a.wrapX:!0})}v(zw,X);function Aw(a){this.C=a.account;this.B=a.map||"";this.f=a.config||{};this.l={};zw.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,maxZoom:void 0!==a.maxZoom?a.maxZoom:18,minZoom:a.minZoom,projection:a.projection,state:"loading",wrapX:a.wrapX});Bw(this)}v(Aw,zw);k=Aw.prototype;k.Kk=function(){return this.f};k.tq=function(a){tb(this.f,a);Bw(this)};k.Xp=function(a){this.f=a||{};Bw(this)}; +function Bw(a){var b=JSON.stringify(a.f);if(a.l[b])Cw(a,a.l[b]);else{var c="https://"+a.C+".cartodb.com/api/v1/map";a.B&&(c+="/named/"+a.B);var d=new XMLHttpRequest;d.addEventListener("load",a.Dl.bind(a,b));d.addEventListener("error",a.Cl.bind(a));d.open("POST",c);d.setRequestHeader("Content-type","application/json");d.send(JSON.stringify(a.f))}} +k.Dl=function(a,b){b=b.target;if(!b.status||200<=b.status&&300>b.status){try{var c=JSON.parse(b.responseText)}catch(d){bu(this,"error");return}Cw(this,c);this.l[a]=c;bu(this,"ready")}else bu(this,"error")};k.Cl=function(){bu(this,"error")};function Cw(a,b){a.jb("https://"+b.cdn_url.https+"/"+a.C+"/api/v1/map/"+b.layergroupid+"/{z}/{x}/{y}.png")};function Y(a){U.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,wrapX:a.wrapX});this.resolution=void 0;this.distance=void 0!==a.distance?a.distance:20;this.features=[];this.geometryFunction=a.geometryFunction||function(a){a=a.V();xa(a instanceof C,10);return a};this.source=a.source;this.source.J("change",Y.prototype.sa,this)}v(Y,U);k=Y.prototype;k.$n=function(){return this.distance};k.ao=function(){return this.source}; +k.Yd=function(a,b,c){this.source.Yd(a,b,c);b!==this.resolution&&(this.clear(),this.resolution=b,Dw(this),this.cd(this.features))};k.Yp=function(a){this.distance=a;this.sa()};k.sa=function(){this.clear();Dw(this);this.cd(this.features);U.prototype.sa.call(this)}; +function Dw(a){if(void 0!==a.resolution){a.features.length=0;for(var b=Oa(),c=a.distance*a.resolution,d=a.source.Xe(),e={},f=0,g=d.length;fm*l?h*g/(m*p):l*g/(n*p),SETVIEWCENTERX:f[0],SETVIEWCENTERY:f[1]};tb(e,this.g);d=Fw(d,e);d=new Js(a,b,c,this.j,d,this.R,this.f);y(d,"change",this.o,this)}else d=null;this.M=d;this.B=this.i;return d};k.jo=function(){return this.f};k.mo=function(a){tb(this.g,a);this.s()};k.lo=function(a){this.M=null;this.f=a;this.s()};function Iw(a){var b=a.imageExtent,c=void 0!==a.crossOrigin?a.crossOrigin:null,d=a.imageLoadFunction?a.imageLoadFunction:Nv;Hv.call(this,{attributions:a.attributions,logo:a.logo,projection:Tb(a.projection)});this.M=new Js(b,void 0,1,this.j,a.url,c,d);this.f=a.imageSize?a.imageSize:null;y(this.M,"change",this.o,this)}v(Iw,Hv);Iw.prototype.Jc=function(a){return qb(a,this.M.G())?this.M:null}; +Iw.prototype.o=function(a){if(2==this.M.getState()){var b=this.M.G(),c=this.M.Y();if(this.f){var d=this.f[0];var e=this.f[1]}else d=c.width,e=c.height;b=Math.ceil(lb(b)/(mb(b)/e));if(b!=d){var b=jd(b,e),f=b.canvas;b.drawImage(c,0,0,d,e,0,0,f.width,f.height);this.M.Og(f)}}Hv.prototype.o.call(this,a)};function Jw(a){a=a||{};Hv.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions});this.pa=void 0!==a.crossOrigin?a.crossOrigin:null;this.g=a.url;this.v=a.imageLoadFunction?a.imageLoadFunction:Nv;this.f=a.params||{};this.l=!0;Kw(this);this.T=a.serverType;this.va=void 0!==a.hidpi?a.hidpi:!0;this.M=null;this.B=[0,0];this.R=0;this.I=void 0!==a.ratio?a.ratio:1.5}v(Jw,Hv);var Lw=[101,101];k=Jw.prototype; +k.so=function(a,b,c,d){if(void 0!==this.g){var e=ob(a,b,0,Lw),f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.f.LAYERS};tb(f,this.f,d);d=Math.floor((e[3]-a[1])/b);f[this.l?"I":"X"]=Math.floor((a[0]-e[0])/b);f[this.l?"J":"Y"]=d;return Mw(this,e,Lw,1,Tb(c),f)}};k.uo=function(){return this.f}; +k.Jc=function(a,b,c,d){if(void 0===this.g)return null;b=Iv(this,b);1==c||this.va&&void 0!==this.T||(c=1);var e=b/c,f=nb(a),g=ob(f,e,0,[Math.ceil(lb(a)/e),Math.ceil(mb(a)/e)]);a=ob(f,e,0,[Math.ceil(this.I*lb(a)/e),Math.ceil(this.I*mb(a)/e)]);if((f=this.M)&&this.R==this.i&&f.resolution==b&&f.a==c&&Va(f.G(),g))return f;g={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};tb(g,this.f);this.B[0]=Math.round(lb(a)/e);this.B[1]=Math.round(mb(a)/e);d=Mw(this,a,this.B,c,d,g); +this.M=new Js(a,b,c,this.j,d,this.pa,this.v);this.R=this.i;y(this.M,"change",this.o,this);return this.M};k.to=function(){return this.v}; +function Mw(a,b,c,d,e,f){xa(void 0!==a.g,9);f[a.l?"CRS":"SRS"]=e.mb;"STYLES"in a.f||(f.STYLES="");if(1!=d)switch(a.T){case "geoserver":d=90*d+.5|0;f.FORMAT_OPTIONS="FORMAT_OPTIONS"in f?f.FORMAT_OPTIONS+(";dpi:"+d):"dpi:"+d;break;case "mapserver":f.MAP_RESOLUTION=90*d;break;case "carmentaserver":case "qgis":f.DPI=90*d;break;default:xa(!1,8)}f.WIDTH=c[0];f.HEIGHT=c[1];c=e.b;var g;a.l&&"ne"==c.substr(0,2)?g=[b[1],b[0],b[3],b[2]]:g=b;f.BBOX=g.join(",");return Fw(a.g,f)}k.vo=function(){return this.g}; +k.wo=function(a){this.M=null;this.v=a;this.s()};k.xo=function(a){a!=this.g&&(this.g=a,this.M=null,this.s())};k.yo=function(a){tb(this.f,a);Kw(this);this.M=null;this.s()};function Kw(a){a.l=0<=Ye(a.f.VERSION||"1.3.0")};function Nw(a){a=a||{};var b;void 0!==a.attributions?b=a.attributions:b=[Ow];zw.call(this,{attributions:b,cacheSize:a.cacheSize,crossOrigin:void 0!==a.crossOrigin?a.crossOrigin:"anonymous",opaque:void 0!==a.opaque?a.opaque:!0,maxZoom:void 0!==a.maxZoom?a.maxZoom:19,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileLoadFunction:a.tileLoadFunction,url:void 0!==a.url?a.url:"https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png",wrapX:a.wrapX})}v(Nw,zw);var Ow=new Ac({html:'© OpenStreetMap contributors.'});Fj.df={};Fj.df.Af=function(){}; +(function(a){function b(a,b,c){if(g)return new ImageData(a,b,c);b=h.createImageData(b,c);b.data.set(a);return b}function c(a){var b=!0;try{new ImageData(10,10)}catch(n){b=!1}return function(c){var d=c.buffers,e=c.meta,f=c.width,g=c.height,h=d.length,l=d[0].byteLength;if(c.imageOps){l=Array(h);for(c=0;cthis.fk;)this.Ed.shift().callback(null,null)};f.prototype.dh=function(){if(0===this.oe&&0Stamen Design, under CC BY 3.0.'}),Ow],Yw={terrain:{Lb:"jpg",opaque:!0},"terrain-background":{Lb:"jpg",opaque:!0},"terrain-labels":{Lb:"png",opaque:!1},"terrain-lines":{Lb:"png",opaque:!1},"toner-background":{Lb:"png",opaque:!0},toner:{Lb:"png",opaque:!0},"toner-hybrid":{Lb:"png",opaque:!1},"toner-labels":{Lb:"png",opaque:!1},"toner-lines":{Lb:"png",opaque:!1},"toner-lite":{Lb:"png", +opaque:!0},watercolor:{Lb:"jpg",opaque:!0}},Xw={terrain:{minZoom:4,maxZoom:18},toner:{minZoom:0,maxZoom:20},watercolor:{minZoom:1,maxZoom:16}};function $w(a){a=a||{};X.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction,url:a.url,urls:a.urls,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.f=a.params||{};this.l=Oa();qw(this,ax(this))}v($w,X);function ax(a){var b=0,c=[],d;for(d in a.f)c[b++]=d+"-"+a.f[d];return c.join("/")}$w.prototype.C=function(){return this.f}; +$w.prototype.nb=function(a){return a}; +$w.prototype.Fc=function(a,b,c){var d=this.tileGrid;d||(d=this.Ta(c));if(!(d.b.length<=a[0])){var e=d.Aa(a,this.l),f=Ma(d.gb(a[0]),this.o);1!=b&&(f=La(f,b,this.o));d={F:"image",FORMAT:"PNG32",TRANSPARENT:!0};tb(d,this.f);var g=this.urls;g?(c=c.mb.split(":").pop(),d.SIZE=f[0]+","+f[1],d.BBOX=e.join(","),d.BBOXSR=c,d.IMAGESR=c,d.DPI=Math.round(d.DPI?d.DPI*b:90*b),a=(1==g.length?g[0]:g[Ia((a[1]<a.status){try{var b=JSON.parse(a.responseText)}catch(c){this.Ve();return}this.og(b)}else this.Ve()};k.zo=function(){this.Ve()};k.pl=function(){return this.f}; +k.og=function(a){var b=Tb("EPSG:4326"),c=this.c;if(a.bounds){var d=Vb(b,c);var e=sb(a.bounds,d)}var f=a.minzoom||0,d=a.maxzoom||22;this.tileGrid=c=xc({extent:zc(c),maxZoom:d,minZoom:f});this.tileUrlFunction=jw(a.tiles,c);if(void 0!==a.attribution&&!this.j){b=void 0!==e?e:b.G();e={};for(var g;f<=d;++f)g=f.toString(),e[g]=[oc(c,b,f)];this.ua([new Ac({html:a.attribution,tileRanges:e})])}this.f=a;bu(this,"ready")};k.Ve=function(){bu(this,"error")};function ex(a){pw.call(this,{projection:Tb("EPSG:3857"),state:"loading"});this.v=void 0!==a.preemptive?a.preemptive:!0;this.l=lw;this.g=void 0;this.f=a.jsonp||!1;if(a.url)if(this.f)gw(a.url,this.pg.bind(this),this.We.bind(this));else{var b=new XMLHttpRequest;b.addEventListener("load",this.Eo.bind(this));b.addEventListener("error",this.Do.bind(this));b.open("GET",a.url);b.send()}else a.tileJSON?this.pg(a.tileJSON):xa(!1,51)}v(ex,pw);k=ex.prototype; +k.Eo=function(a){a=a.target;if(!a.status||200<=a.status&&300>a.status){try{var b=JSON.parse(a.responseText)}catch(c){this.We();return}this.pg(b)}else this.We()};k.Do=function(){this.We()};k.ml=function(){return this.g};k.zk=function(a,b,c,d,e){this.tileGrid?(b=this.tileGrid.Be(a,b),fx(this.Nc(b[0],b[1],b[2],1,this.c),a,c,d,e)):!0===e?setTimeout(function(){c.call(d,null)},0):c.call(d,null)};k.We=function(){bu(this,"error")}; +k.pg=function(a){var b=Tb("EPSG:4326"),c=this.c;if(a.bounds){var d=Vb(b,c);var e=sb(a.bounds,d)}var f=a.minzoom||0,d=a.maxzoom||22;this.tileGrid=c=xc({extent:zc(c),maxZoom:d,minZoom:f});this.g=a.template;var g=a.grids;if(g){this.l=jw(g,c);if(void 0!==a.attribution){b=void 0!==e?e:b.G();for(e={};f<=d;++f)g=f.toString(),e[g]=[oc(c,b,f)];this.ua([new Ac({html:a.attribution,tileRanges:e})])}bu(this,"ready")}else bu(this,"error")}; +k.Nc=function(a,b,c,d,e){var f=this.Sb(a,b,c);if(this.a.b.hasOwnProperty(f))return this.a.get(f);a=[a,b,c];b=rw(this,a,e);d=this.l(b,d,e);d=new gx(a,void 0!==d?0:4,void 0!==d?d:"",this.tileGrid.Aa(a),this.v,this.f);this.a.set(f,d);return d};k.Ug=function(a,b,c){a=this.Sb(a,b,c);this.a.b.hasOwnProperty(a)&&this.a.get(a)};function gx(a,b,c,d,e,f){Ls.call(this,a,b);this.o=c;this.a=d;this.v=e;this.c=this.j=this.g=null;this.l=f}v(gx,Ls);k=gx.prototype;k.Y=function(){return null}; +k.getData=function(a){if(!this.g||!this.j)return null;var b=this.g[Math.floor((1-(a[1]-this.a[1])/(this.a[3]-this.a[1]))*this.g.length)];if("string"!==typeof b)return null;b=b.charCodeAt(Math.floor((a[0]-this.a[0])/(this.a[2]-this.a[0])*b.length));93<=b&&b--;35<=b&&b--;b-=32;a=null;b in this.j&&(b=this.j[b],this.c&&b in this.c?a=this.c[b]:a=b);return a}; +function fx(a,b,c,d,e){0==a.state&&!0===e?(Jc(a,"change",function(){c.call(d,this.getData(b))},a),hx(a)):!0===e?setTimeout(function(){c.call(d,this.getData(b))}.bind(a),0):c.call(d,a.getData(b))}k.bb=function(){return this.o};k.De=function(){this.state=3;this.s()};k.Ji=function(a){this.g=a.grid;this.j=a.keys;this.c=a.data;this.state=4;this.s()}; +function hx(a){if(0==a.state)if(a.state=1,a.l)gw(a.o,a.Ji.bind(a),a.De.bind(a));else{var b=new XMLHttpRequest;b.addEventListener("load",a.Co.bind(a));b.addEventListener("error",a.Bo.bind(a));b.open("GET",a.o);b.send()}}k.Co=function(a){a=a.target;if(!a.status||200<=a.status&&300>a.status){try{var b=JSON.parse(a.responseText)}catch(c){this.De();return}this.Ji(b)}else this.De()};k.Bo=function(){this.De()};k.load=function(){this.v&&hx(this)};function ix(a){a=a||{};var b=a.params||{};X.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,opaque:!("TRANSPARENT"in b?b.TRANSPARENT:1),projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction,url:a.url,urls:a.urls,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.C=void 0!==a.gutter?a.gutter:0;this.f=b;this.l=!0;this.B=a.serverType;this.T=void 0!==a.hidpi?a.hidpi:!0;this.R=""; +jx(this);this.fa=Oa();kx(this);qw(this,lx(this))}v(ix,X);k=ix.prototype; +k.Fo=function(a,b,c,d){c=Tb(c);var e=this.tileGrid;e||(e=this.Ta(c));b=e.Be(a,b);if(!(e.b.length<=b[0])){var f=e.Da(b[0]),g=e.Aa(b,this.fa),e=Ma(e.gb(b[0]),this.o),h=this.C;h&&(e=Ka(e,h,this.o),g=Qa(g,f*h,g));h={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.f.LAYERS};tb(h,this.f,d);d=Math.floor((g[3]-a[1])/f);h[this.l?"I":"X"]=Math.floor((a[0]-g[0])/f);h[this.l?"J":"Y"]=d;return mx(this,b,e,g,1,c,h)}};k.Xf=function(){return this.C}; +k.Sb=function(a,b,c){return this.R+X.prototype.Sb.call(this,a,b,c)};k.Go=function(){return this.f}; +function mx(a,b,c,d,e,f,g){var h=a.urls;if(h){g.WIDTH=c[0];g.HEIGHT=c[1];g[a.l?"CRS":"SRS"]=f.mb;"STYLES"in a.f||(g.STYLES="");if(1!=e)switch(a.B){case "geoserver":c=90*e+.5|0;g.FORMAT_OPTIONS="FORMAT_OPTIONS"in g?g.FORMAT_OPTIONS+(";dpi:"+c):"dpi:"+c;break;case "mapserver":g.MAP_RESOLUTION=90*e;break;case "carmentaserver":case "qgis":g.DPI=90*e;break;default:xa(!1,52)}f=f.b;a.l&&"ne"==f.substr(0,2)&&(a=d[0],d[0]=d[1],d[1]=a,a=d[2],d[2]=d[3],d[3]=a);g.BBOX=d.join(",");return Fw(1==h.length?h[0]:h[Ia((b[1]<< +b[0])+b[2],h.length)],g)}}k.nb=function(a){return this.T&&void 0!==this.B?a:1};function jx(a){var b=0,c=[];if(a.urls){var d;var e=0;for(d=a.urls.length;ef||d>f;)e.push([Math.ceil(c/f),Math.ceil(d/f)]),f+=f;break;case wx:for(;c>f||d>f;)e.push([Math.ceil(c/f),Math.ceil(d/f)]),c>>=1,d>>=1;break;default:xa(!1,53)}e.push([1,1]);e.reverse();for(var f=[1],g=[0],d=1,c=e.length;d=b+this.b&&h.height>=c+this.b)return f={offsetX:h.x+this.b,offsetY:h.y+this.b,image:this.f},this.c[a]=f,d.call(e,this.i,h.x+this.b,h.y+this.b),a=g,b+=this.b,d=c+this.b,h.width-b>h.height-d?(c={x:h.x+b,y:h.y,width:h.width-b,height:h.height},b={x:h.x,y:h.y+d,width:b,height:h.height-d},zx(this,a,c,b)):(c={x:h.x+b,y:h.y,width:h.width-b,height:d},b={x:h.x,y:h.y+d,width:h.width,height:h.height-d}, +zx(this,a,c,b)),f}return null};function zx(a,b,c,d){b=[b,1];0this.i||c+this.b>this.i)return null;d=Bx(this,!1,a,b,c,d,f);if(!d)return null;a=Bx(this,!0,a,b,c,e?e:ua,f);return{offsetX:d.offsetX,offsetY:d.offsetY,image:d.image,Zl:a.image}}; +function Bx(a,b,c,d,e,f,g){var h=b?a.g:a.f,l;var m=0;for(l=h.length;ma?sd(2*a):1-sd(2*(a-.5))}); +t("ol.extent.boundingExtent",Na);t("ol.extent.buffer",Qa);t("ol.extent.containsCoordinate",Ta);t("ol.extent.containsExtent",Va);t("ol.extent.containsXY",Ua);t("ol.extent.createEmpty",Oa);t("ol.extent.equals",bb);t("ol.extent.extend",cb);t("ol.extent.getArea",jb);t("ol.extent.getBottomLeft",eb);t("ol.extent.getBottomRight",gb);t("ol.extent.getCenter",nb);t("ol.extent.getHeight",mb);t("ol.extent.getIntersection",pb);t("ol.extent.getSize",function(a){return[a[2]-a[0],a[3]-a[1]]}); +t("ol.extent.getTopLeft",ib);t("ol.extent.getTopRight",hb);t("ol.extent.getWidth",lb);t("ol.extent.intersects",qb);t("ol.extent.isEmpty",kb);t("ol.extent.applyTransform",sb);t("ol.Feature",H);H.prototype.clone=H.prototype.clone;H.prototype.getGeometry=H.prototype.V;H.prototype.getId=H.prototype.wm;H.prototype.getGeometryName=H.prototype.Qk;H.prototype.getStyle=H.prototype.xm;H.prototype.getStyleFunction=H.prototype.Lc;H.prototype.setGeometry=H.prototype.Ra;H.prototype.setStyle=H.prototype.hg; +H.prototype.setId=H.prototype.jc;H.prototype.setGeometryName=H.prototype.Tc;t("ol.featureloader.xhr",Dl);t("ol.Geolocation",xs);xs.prototype.getAccuracy=xs.prototype.Dk;xs.prototype.getAccuracyGeometry=xs.prototype.Ek;xs.prototype.getAltitude=xs.prototype.Gk;xs.prototype.getAltitudeAccuracy=xs.prototype.Hk;xs.prototype.getHeading=xs.prototype.ym;xs.prototype.getPosition=xs.prototype.zm;xs.prototype.getProjection=xs.prototype.Uh;xs.prototype.getSpeed=xs.prototype.ll;xs.prototype.getTracking=xs.prototype.Vh; +xs.prototype.getTrackingOptions=xs.prototype.Gh;xs.prototype.setProjection=xs.prototype.Wh;xs.prototype.setTracking=xs.prototype.Ke;xs.prototype.setTrackingOptions=xs.prototype.wj;t("ol.Graticule",Ds);Ds.prototype.getMap=Ds.prototype.Cm;Ds.prototype.getMeridians=Ds.prototype.al;Ds.prototype.getParallels=Ds.prototype.hl;Ds.prototype.setMap=Ds.prototype.setMap;t("ol.has.DEVICE_PIXEL_RATIO",Sd);t("ol.has.CANVAS",Ud);t("ol.has.DEVICE_ORIENTATION",Vd);t("ol.has.GEOLOCATION",Wd);t("ol.has.TOUCH",Xd); +t("ol.has.WEBGL",Md);Js.prototype.getImage=Js.prototype.Y;Js.prototype.load=Js.prototype.load;Os.prototype.getImage=Os.prototype.Y;t("ol.inherits",v);t("ol.interaction.defaults",qh);t("ol.Kinetic",kg);t("ol.loadingstrategy.all",Zt);t("ol.loadingstrategy.bbox",function(a){return[a]});t("ol.loadingstrategy.tile",function(a){return function(b,c){c=a.tc(c);b=oc(a,b,c);var d=[];c=[c,0,0];for(c[1]=b.ca;c[1]<=b.$;++c[1])for(c[2]=b.da;c[2]<=b.ia;++c[2])d.push(a.Aa(c));return d}});t("ol.Map",G); +G.prototype.addControl=G.prototype.kk;G.prototype.addInteraction=G.prototype.lk;G.prototype.addLayer=G.prototype.ih;G.prototype.addOverlay=G.prototype.jh;G.prototype.forEachFeatureAtPixel=G.prototype.we;G.prototype.forEachLayerAtPixel=G.prototype.Im;G.prototype.hasFeatureAtPixel=G.prototype.Yl;G.prototype.getEventCoordinate=G.prototype.Tf;G.prototype.getEventPixel=G.prototype.xe;G.prototype.getTarget=G.prototype.ag;G.prototype.getTargetElement=G.prototype.jd;G.prototype.getCoordinateFromPixel=G.prototype.Wa; +G.prototype.getControls=G.prototype.Lk;G.prototype.getOverlays=G.prototype.fl;G.prototype.getOverlayById=G.prototype.el;G.prototype.getInteractions=G.prototype.Sk;G.prototype.getLayerGroup=G.prototype.Kc;G.prototype.getLayers=G.prototype.Xh;G.prototype.getPixelFromCoordinate=G.prototype.Ja;G.prototype.getSize=G.prototype.Ob;G.prototype.getView=G.prototype.Z;G.prototype.getViewport=G.prototype.sl;G.prototype.renderSync=G.prototype.Tp;G.prototype.render=G.prototype.render; +G.prototype.removeControl=G.prototype.Mp;G.prototype.removeInteraction=G.prototype.Np;G.prototype.removeLayer=G.prototype.Pp;G.prototype.removeOverlay=G.prototype.Qp;G.prototype.setLayerGroup=G.prototype.qj;G.prototype.setSize=G.prototype.Qg;G.prototype.setTarget=G.prototype.Le;G.prototype.setView=G.prototype.iq;G.prototype.updateSize=G.prototype.Ad;Jd.prototype.originalEvent=Jd.prototype.originalEvent;Jd.prototype.pixel=Jd.prototype.pixel;Jd.prototype.coordinate=Jd.prototype.coordinate; +Jd.prototype.dragging=Jd.prototype.dragging;Id.prototype.map=Id.prototype.map;Id.prototype.frameState=Id.prototype.frameState;t("ol.Object",Tc);Tc.prototype.get=Tc.prototype.get;Tc.prototype.getKeys=Tc.prototype.O;Tc.prototype.getProperties=Tc.prototype.N;Tc.prototype.set=Tc.prototype.set;Tc.prototype.setProperties=Tc.prototype.H;Tc.prototype.unset=Tc.prototype.P;Xc.prototype.key=Xc.prototype.key;Xc.prototype.oldValue=Xc.prototype.oldValue;t("ol.Observable",Sc); +t("ol.Observable.unByKey",function(a){if(Array.isArray(a))for(var b=0,c=a.length;be&&(e=0);var f=c.TileMatrixSetLink[e].TileMatrixSet;var g=c.TileMatrixSetLink[e].TileMatrixSetLimits;var h=c.Format[0];"format"in b&&(h=b.format);e=sa(c.Style,function(a){return"style"in b?a.Title==b.style:a.isDefault});0>e&&(e=0);e=c.Style[e].Identifier;var l={};"Dimension"in c&&c.Dimension.forEach(function(a){var b=a.Identifier,c=a.Default;void 0===c&&(c=a.Value[0]);l[b]=c});var m=na(a.Contents.TileMatrixSet,function(a){return a.Identifier==f});var n="projection"in b?Tb(b.projection): +Tb(m.SupportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/,"$1:$3"));var p=c.WGS84BoundingBox;if(void 0!==p){var q=Tb("EPSG:4326").G();q=p[0]==q[0]&&p[2]==q[2];var r=hc(p,"EPSG:4326",n);(p=n.G())&&(Va(p,r)||(r=void 0))}g=sx(m,r,g);var u=[],m=b.requestEncoding,m=void 0!==m?m:"";if("OperationsMetadata"in a&&"GetTile"in a.OperationsMetadata)for(a=a.OperationsMetadata.GetTile.DCP.HTTP.Get,r=0,p=a.length;r div",this.Base.container,!0);n<=e?(this.Base.container.style.right="auto",this.Base.container.style.left=t[0]+5+"px"):(this.Base.container.style.left="auto",this.Base.container.style.right="15px"),i<=o?(this.Base.container.style.bottom="auto",this.Base.container.style.top=t[1]-10+"px"):(this.Base.container.style.top="auto",this.Base.container.style.bottom=0),d.removeClass(this.Base.container,l.hidden),a.length&&(this.submenu.lastLeft=e<2*n?"-"+n+"px":this.submenu.left,a.forEach(function(t){var e=d.getViewportSize(),n=d.offset(t),i=n.height;o-i<0&&(i=i-(e.h-n.top),t.style.top="-"+i+"px"),t.style.left=s.submenu.lastLeft}))},e.prototype.openMenu=function(t,e){this.Base.dispatchEvent({type:o,pixel:t,coordinate:e}),this.opened=!0,this.positionContainer(t)},e.prototype.closeMenu=function(){this.opened=!1,d.addClass(this.Base.container,l.hidden),this.Base.dispatchEvent({type:a})},e.prototype.setListeners=function(){this.viewport.addEventListener(this.Base.options.eventType,this.eventHandler,!1)},e.prototype.removeListeners=function(){this.viewport.removeEventListener(this.Base.options.eventType,this.eventHandler,!1)},e.prototype.handleEvent=function(e){var n=this;this.coordinateClicked=this.map.getEventCoordinate(e),this.pixelClicked=this.map.getEventPixel(e),this.Base.dispatchEvent({type:s,pixel:this.pixelClicked,coordinate:this.coordinateClicked}),this.Base.disabled||(this.Base.options.eventType===r&&(e.stopPropagation(),e.preventDefault()),this.openMenu(this.pixelClicked,this.coordinateClicked),e.target.addEventListener("mousedown",{handleEvent:function(t){n.closeMenu(),e.target.removeEventListener(t.type,this,!1)}},!1))},e.prototype.setItemListener=function(t,e){var n,i=this;t&&"function"==typeof this.items[e].callback&&(n=this.items[e].callback,t.addEventListener("click",function(t){t.preventDefault();t={coordinate:i.getCoordinateClicked(),data:i.items[e].data||null};i.closeMenu(),n(t,i.map)},!1))};function u(t){d.assert("object"==typeof(t=void 0===t?{}:t),"@param `opt_options` should be object type!"),"default_items"in t&&(c.defaultItems=t.default_items),this.options=d.mergeOptions(c,t),this.disabled=!1,this.Internal=new e(this),this.Html=new n(this),i.call(this,{element:this.container})}return n.prototype.createContainer=function(t){var e=document.createElement("div"),n=document.createElement("ul"),i=[l.container,l.OL_unselectable];return t&&i.push(l.hidden),e.className=i.join(" "),e.style.width=parseInt(this.Base.options.width,10)+"px",e.appendChild(n),e},n.prototype.createMenu=function(){var t=[];return"items"in this.Base.options?t=this.Base.options.defaultItems?this.Base.options.items.concat(h):this.Base.options.items:this.Base.options.defaultItems&&(t=h),0!==t.length&&void t.forEach(this.addMenuEntry,this)},n.prototype.addMenuEntry=function(t){var e,n,i=this;t.items&&Array.isArray(t.items)?(t.classname=t.classname||"",d.contains(l.submenu,t.classname)||(t.classname=t.classname.length?" "+l.submenu:l.submenu),e=this.generateHtmlAndPublish(this.container,t),(n=this.createContainer()).style.left=this.Base.Internal.submenu.lastLeft||this.Base.Internal.submenu.left,e.appendChild(n),t.items.forEach(function(t){i.generateHtmlAndPublish(n,t,!0)})):this.generateHtmlAndPublish(this.container,t)},n.prototype.generateHtmlAndPublish=function(t,e,n){var i,s,o,a=!1,r=d.getUniqueId();return"string"==typeof e&&"-"===e.trim()?(i=['
  • ',"
  • "].join(""),s=d.createFragment(i),o=[].slice.call(s.childNodes,0)[0],t.firstChild.appendChild(s),a=!0):(e.classname=e.classname||"",i=""+e.text+"",s=d.createFragment(i),o=document.createElement("li"),e.icon&&(""===e.classname?e.classname=l.icon:-1===e.classname.indexOf(l.icon)&&(e.classname+=" "+l.icon),o.setAttribute("style","background-image:url("+e.icon+")")),o.id=r,o.className=e.classname,o.appendChild(s),t.firstChild.appendChild(o)),this.Base.Internal.items[r]={id:r,submenu:n||0,separator:a,callback:e.callback,data:e.data||null},this.Base.Internal.setItemListener(o,r),o},n.prototype.removeMenuEntry=function(t){var e=d.find("#"+t,this.container.firstChild);e&&this.container.firstChild.removeChild(e),delete this.Base.Internal.items[t]},n.prototype.cloneAndGetLineHeight=function(){var t=this.container.cloneNode(),e=d.createFragment("Foo"),n=d.createFragment("Foo"),i=document.createElement("li"),s=document.createElement("li"),e=(i.appendChild(e),s.appendChild(n),t.appendChild(i),t.appendChild(s),this.container.parentNode.appendChild(t),t.offsetHeight/2);return this.container.parentNode.removeChild(t),e},(i=ol.control.Control)&&(u.__proto__=i),((u.prototype=Object.create(i&&i.prototype)).constructor=u).prototype.clear=function(){var e=this;Object.keys(this.Internal.items).forEach(function(t){e.Html.removeMenuEntry(t)})},u.prototype.close=function(){this.Internal.closeMenu()},u.prototype.enable=function(){this.disabled=!1},u.prototype.disable=function(){this.disabled=!0},u.prototype.getDefaultItems=function(){return h},u.prototype.extend=function(t){d.assert(Array.isArray(t),"@param `arr` should be an Array."),t.forEach(this.push,this)},u.prototype.isOpened=function(){return this.isOpen()},u.prototype.isOpen=function(){return this.Internal.opened},u.prototype.updatePosition=function(t){d.assert(Array.isArray(t),"@param `pixel` should be an Array."),this.isOpen()&&this.Internal.positionContainer(t)},u.prototype.pop=function(){var t=Object.keys(this.Internal.items);this.Html.removeMenuEntry(t[t.length-1])},u.prototype.push=function(t){d.assert(d.isDefAndNotNull(t),"@param `item` must be informed."),this.Html.addMenuEntry(t)},u.prototype.shift=function(){this.Html.removeMenuEntry(Object.keys(this.Internal.items)[0])},u.prototype.setMap=function(t){ol.control.Control.prototype.setMap.call(this,t),t?this.Internal.init(t,this):this.Internal.removeListeners()},u}) \ No newline at end of file +((t,e)=>{"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.ContextMenu=e()})(this,function(){function e(t){return this.Base=t,this.map=void 0,this.viewport=void 0,this.coordinateClicked=void 0,this.pixelClicked=void 0,this.lineHeight=0,this.items={},this.opened=!1,this.submenu={left:t.options.width-15+"px",lastLeft:""},this.eventHandler=this.handleEvent.bind(this),this}function n(t){return this.Base=t,this.Base.container=this.container=this.createContainer(),this}var i,t="ol-ctx-menu",s="beforeopen",o="open",a="close",r="contextmenu",l={container:t+"-container",separator:t+"-separator",submenu:t+"-submenu",hidden:t+"-hidden",icon:t+"-icon",zoomIn:t+"-zoom-in",zoomOut:t+"-zoom-out",OL_unselectable:"ol-unselectable"},c={width:150,scrollAt:4,eventType:r,defaultItems:!0},h=[{text:"Zoom In",classname:[l.zoomIn,l.icon].join(" "),callback:function(t,e){e=e.getView();e.animate({zoom:+e.getZoom()+1,duration:700,center:t.coordinate})}},{text:"Zoom Out",classname:[l.zoomOut,l.icon].join(" "),callback:function(t,e){e=e.getView();e.animate({zoom:+e.getZoom()-1,duration:700,center:t.coordinate})}}],d={isNumeric:function(t){return/^\d+$/.test(t)},classRegex:function(t){return new RegExp("(^|\\s+) "+t+" (\\s+|$)")},addClass:function(t,e,n){var i=this;if(Array.isArray(t))t.forEach(function(t){i.addClass(t,e)});else for(var s=Array.isArray(e)?e:e.split(/\s+/),o=s.length;o--;)i.hasClass(t,s[o])||i._addClass(t,s[o],n)},_addClass:function(t,e,n){var i=this;t.classList?t.classList.add(e):t.className=(t.className+" "+e).trim(),n&&this.isNumeric(n)&&window.setTimeout(function(){i._removeClass(t,e)},n)},removeClass:function(t,e,n){var i=this;if(Array.isArray(t))t.forEach(function(t){i.removeClass(t,e,n)});else for(var s=Array.isArray(e)?e:e.split(/\s+/),o=s.length;o--;)i.hasClass(t,s[o])&&i._removeClass(t,s[o],n)},_removeClass:function(t,e,n){var i=this;t.classList?t.classList.remove(e):t.className=t.className.replace(this.classRegex(e)," ").trim(),n&&this.isNumeric(n)&&window.setTimeout(function(){i._addClass(t,e)},n)},hasClass:function(t,e){return t.classList?t.classList.contains(e):this.classRegex(e).test(t.className)},toggleClass:function(t,e){var n=this;return Array.isArray(t)?void t.forEach(function(t){n.toggleClass(t,e)}):void(t.classList?t.classList.toggle(e):this.hasClass(t,e)?this._removeClass(t,e):this._addClass(t,e))},$:function(t){return t="#"===t[0]?t.substr(1,t.length):t,document.getElementById(t)},isElement:function(t){return"HTMLElement"in window?!!t&&t instanceof HTMLElement:!!t&&"object"==typeof t&&1===t.nodeType&&!!t.nodeName},find:function(t,e,n){void 0===e&&(e=window.document);var i=Array.prototype.slice,s=[];if(/^(#?[\w-]+|\.[\w-.]+)$/.test(t))switch(t[0]){case"#":s=[this.$(t.substr(1))];break;case".":s=i.call(e.getElementsByClassName(t.substr(1).replace(/\./g," ")));break;default:s=i.call(e.getElementsByTagName(t))}else s=i.call(e.querySelectorAll(t));return n?s:s[0]},offset:function(t){var e=t.getBoundingClientRect(),n=document.documentElement;return{left:e.left+window.pageXOffset-n.clientLeft,top:e.top+window.pageYOffset-n.clientTop,width:t.offsetWidth,height:t.offsetHeight}},getViewportSize:function(){return{w:window.innerWidth||document.documentElement.clientWidth,h:window.innerHeight||document.documentElement.clientHeight}},getAllChildren:function(t,e){return[].slice.call(t.getElementsByTagName(e))},isEmpty:function(t){return!t||0===t.length},emptyArray:function(t){for(;t.length;)t.pop()},removeAllChildren:function(t){for(;t.firstChild;)t.removeChild(t.firstChild)},mergeOptions:function(t,e){var n,i,s={};for(n in t)s[n]=t[n];for(i in e)s[i]=e[i];return s},createFragment:function(t){var e=document.createDocumentFragment(),n=document.createElement("div");for(n.innerHTML=t;n.firstChild;)e.appendChild(n.firstChild);return e},contains:function(t,e){return!!~e.indexOf(t)},getUniqueId:function(){return"_"+Math.random().toString(36).substr(2,9)},isDefAndNotNull:function(t){return null!=t},assertEqual:function(t,e,n){if(t!==e)throw new Error(n+" mismatch: "+t+" != "+e)},assert:function(t,e){if(void 0===e&&(e="Assertion failed"),!t){if("undefined"!=typeof Error)throw new Error(e);throw e}}};e.prototype.init=function(t){this.map=t,this.viewport=t.getViewport(),this.setListeners(),this.Base.Html.createMenu(),this.lineHeight=0 div",this.Base.container,!0);n<=e?(this.Base.container.style.right="auto",this.Base.container.style.left=t[0]+5+"px"):(this.Base.container.style.left="auto",this.Base.container.style.right="15px"),i<=o?(this.Base.container.style.bottom="auto",this.Base.container.style.top=t[1]-10+"px"):(this.Base.container.style.top="auto",this.Base.container.style.bottom=0),d.removeClass(this.Base.container,l.hidden),a.length&&(this.submenu.lastLeft=e<2*n?"-"+n+"px":this.submenu.left,a.forEach(function(t){var e=d.getViewportSize(),n=d.offset(t),i=n.height;o-i<0&&(i=i-(e.h-n.top),t.style.top="-"+i+"px"),t.style.left=s.submenu.lastLeft}))},e.prototype.openMenu=function(t,e){this.Base.dispatchEvent({type:o,pixel:t,coordinate:e}),this.opened=!0,this.positionContainer(t)},e.prototype.closeMenu=function(){this.opened=!1,d.addClass(this.Base.container,l.hidden),this.Base.dispatchEvent({type:a})},e.prototype.setListeners=function(){this.viewport.addEventListener(this.Base.options.eventType,this.eventHandler,!1)},e.prototype.removeListeners=function(){this.viewport.removeEventListener(this.Base.options.eventType,this.eventHandler,!1)},e.prototype.handleEvent=function(e){var n=this;this.coordinateClicked=this.map.getEventCoordinate(e),this.pixelClicked=this.map.getEventPixel(e),this.Base.dispatchEvent({type:s,pixel:this.pixelClicked,coordinate:this.coordinateClicked}),this.Base.disabled||(this.Base.options.eventType===r&&(e.stopPropagation(),e.preventDefault()),this.openMenu(this.pixelClicked,this.coordinateClicked),e.target.addEventListener("mousedown",{handleEvent:function(t){n.closeMenu(),e.target.removeEventListener(t.type,this,!1)}},!1))},e.prototype.setItemListener=function(t,e){var n,i=this;t&&"function"==typeof this.items[e].callback&&(n=this.items[e].callback,t.addEventListener("click",function(t){t.preventDefault();t={coordinate:i.getCoordinateClicked(),data:i.items[e].data||null};i.closeMenu(),n(t,i.map)},!1))};function u(t){d.assert("object"==typeof(t=void 0===t?{}:t),"@param `opt_options` should be object type!"),"default_items"in t&&(c.defaultItems=t.default_items),this.options=d.mergeOptions(c,t),this.disabled=!1,this.Internal=new e(this),this.Html=new n(this),i.call(this,{element:this.container})}return n.prototype.createContainer=function(t){var e=document.createElement("div"),n=document.createElement("ul"),i=[l.container,l.OL_unselectable];return t&&i.push(l.hidden),e.className=i.join(" "),e.style.width=parseInt(this.Base.options.width,10)+"px",e.appendChild(n),e},n.prototype.createMenu=function(){var t=[];return"items"in this.Base.options?t=this.Base.options.defaultItems?this.Base.options.items.concat(h):this.Base.options.items:this.Base.options.defaultItems&&(t=h),0!==t.length&&void t.forEach(this.addMenuEntry,this)},n.prototype.addMenuEntry=function(t){var e,n,i=this;t.items&&Array.isArray(t.items)?(t.classname=t.classname||"",d.contains(l.submenu,t.classname)||(t.classname=t.classname.length?" "+l.submenu:l.submenu),e=this.generateHtmlAndPublish(this.container,t),(n=this.createContainer()).style.left=this.Base.Internal.submenu.lastLeft||this.Base.Internal.submenu.left,e.appendChild(n),t.items.forEach(function(t){i.generateHtmlAndPublish(n,t,!0)})):this.generateHtmlAndPublish(this.container,t)},n.prototype.generateHtmlAndPublish=function(t,e,n){var i,s,o,a=!1,r=d.getUniqueId();return"string"==typeof e&&"-"===e.trim()?(i=['
  • ',"
  • "].join(""),s=d.createFragment(i),o=[].slice.call(s.childNodes,0)[0],t.firstChild.appendChild(s),a=!0):(e.classname=e.classname||"",s=d.createFragment(i=""+e.text+""),o=document.createElement("li"),e.icon&&(""===e.classname?e.classname=l.icon:-1===e.classname.indexOf(l.icon)&&(e.classname+=" "+l.icon),o.setAttribute("style","background-image:url("+e.icon+")")),o.id=r,o.className=e.classname,o.appendChild(s),t.firstChild.appendChild(o)),this.Base.Internal.items[r]={id:r,submenu:n||0,separator:a,callback:e.callback,data:e.data||null},this.Base.Internal.setItemListener(o,r),o},n.prototype.removeMenuEntry=function(t){var e=d.find("#"+t,this.container.firstChild);e&&this.container.firstChild.removeChild(e),delete this.Base.Internal.items[t]},n.prototype.cloneAndGetLineHeight=function(){var t=this.container.cloneNode(),e=d.createFragment("Foo"),n=d.createFragment("Foo"),i=document.createElement("li"),s=document.createElement("li"),e=(i.appendChild(e),s.appendChild(n),t.appendChild(i),t.appendChild(s),this.container.parentNode.appendChild(t),t.offsetHeight/2);return this.container.parentNode.removeChild(t),e},(i=ol.control.Control)&&(u.__proto__=i),((u.prototype=Object.create(i&&i.prototype)).constructor=u).prototype.clear=function(){var e=this;Object.keys(this.Internal.items).forEach(function(t){e.Html.removeMenuEntry(t)})},u.prototype.close=function(){this.Internal.closeMenu()},u.prototype.enable=function(){this.disabled=!1},u.prototype.disable=function(){this.disabled=!0},u.prototype.getDefaultItems=function(){return h},u.prototype.extend=function(t){d.assert(Array.isArray(t),"@param `arr` should be an Array."),t.forEach(this.push,this)},u.prototype.isOpened=function(){return this.isOpen()},u.prototype.isOpen=function(){return this.Internal.opened},u.prototype.updatePosition=function(t){d.assert(Array.isArray(t),"@param `pixel` should be an Array."),this.isOpen()&&this.Internal.positionContainer(t)},u.prototype.pop=function(){var t=Object.keys(this.Internal.items);this.Html.removeMenuEntry(t[t.length-1])},u.prototype.push=function(t){d.assert(d.isDefAndNotNull(t),"@param `item` must be informed."),this.Html.addMenuEntry(t)},u.prototype.shift=function(){this.Html.removeMenuEntry(Object.keys(this.Internal.items)[0])},u.prototype.setMap=function(t){ol.control.Control.prototype.setMap.call(this,t),t?this.Internal.init(t,this):this.Internal.removeListeners()},u}) \ No newline at end of file diff --git a/public/scripts/purify-min.js b/public/scripts/purify-min.js new file mode 100644 index 00000000..a30c02bf --- /dev/null +++ b/public/scripts/purify-min.js @@ -0,0 +1,3 @@ +/*! @license DOMPurify 3.1.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.6/LICENSE */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=b(Array.prototype.forEach),m=b(Array.prototype.pop),p=b(Array.prototype.push),f=b(String.prototype.toLowerCase),d=b(String.prototype.toString),h=b(String.prototype.match),g=b(String.prototype.replace),T=b(String.prototype.indexOf),y=b(String.prototype.trim),E=b(Object.prototype.hasOwnProperty),_=b(RegExp.prototype.test),A=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n1?n-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:f;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function R(e){for(let t=0;t/gm),B=a(/\${[\w\W]*}/gm),W=a(/^data-[\-\w.\u00B7-\uFFFF]/),G=a(/^aria-[\-\w]+$/),Y=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),j=a(/^(?:\w+script|data):/i),X=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),q=a(/^html$/i),$=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var K=Object.freeze({__proto__:null,MUSTACHE_EXPR:H,ERB_EXPR:z,TMPLIT_EXPR:B,DATA_ATTR:W,ARIA_ATTR:G,IS_ALLOWED_URI:Y,IS_SCRIPT_OR_DATA:j,ATTR_WHITESPACE:X,DOCTYPE_NAME:q,CUSTOM_ELEMENT:$});const V=1,Z=3,J=7,Q=8,ee=9,te=function(){return"undefined"==typeof window?null:window};var ne=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:te();const o=e=>t(e);if(o.version="3.1.6",o.removed=[],!n||!n.document||n.document.nodeType!==ee)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:b,Element:R,NodeFilter:H,NamedNodeMap:z=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:B,DOMParser:W,trustedTypes:G}=n,j=R.prototype,X=C(j,"cloneNode"),$=C(j,"remove"),ne=C(j,"nextSibling"),oe=C(j,"childNodes"),re=C(j,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let ie,ae="";const{implementation:le,createNodeIterator:ce,createDocumentFragment:se,getElementsByTagName:ue}=r,{importNode:me}=a;let pe={};o.isSupported="function"==typeof e&&"function"==typeof re&&le&&void 0!==le.createHTMLDocument;const{MUSTACHE_EXPR:fe,ERB_EXPR:de,TMPLIT_EXPR:he,DATA_ATTR:ge,ARIA_ATTR:Te,IS_SCRIPT_OR_DATA:ye,ATTR_WHITESPACE:Ee,CUSTOM_ELEMENT:_e}=K;let{IS_ALLOWED_URI:Ae}=K,Ne=null;const be=S({},[...L,...D,...v,...x,...M]);let Se=null;const Re=S({},[...I,...U,...P,...F]);let we=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ce=null,Le=null,De=!0,ve=!0,Oe=!1,xe=!0,ke=!1,Me=!0,Ie=!1,Ue=!1,Pe=!1,Fe=!1,He=!1,ze=!1,Be=!0,We=!1,Ge=!0,Ye=!1,je={},Xe=null;const qe=S({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let $e=null;const Ke=S({},["audio","video","img","source","image","track"]);let Ve=null;const Ze=S({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Je="http://www.w3.org/1998/Math/MathML",Qe="http://www.w3.org/2000/svg",et="http://www.w3.org/1999/xhtml";let tt=et,nt=!1,ot=null;const rt=S({},[Je,Qe,et],d);let it=null;const at=["application/xhtml+xml","text/html"];let lt=null,ct=null;const st=r.createElement("form"),ut=function(e){return e instanceof RegExp||e instanceof Function},mt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ct||ct!==e){if(e&&"object"==typeof e||(e={}),e=w(e),it=-1===at.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,lt="application/xhtml+xml"===it?d:f,Ne=E(e,"ALLOWED_TAGS")?S({},e.ALLOWED_TAGS,lt):be,Se=E(e,"ALLOWED_ATTR")?S({},e.ALLOWED_ATTR,lt):Re,ot=E(e,"ALLOWED_NAMESPACES")?S({},e.ALLOWED_NAMESPACES,d):rt,Ve=E(e,"ADD_URI_SAFE_ATTR")?S(w(Ze),e.ADD_URI_SAFE_ATTR,lt):Ze,$e=E(e,"ADD_DATA_URI_TAGS")?S(w(Ke),e.ADD_DATA_URI_TAGS,lt):Ke,Xe=E(e,"FORBID_CONTENTS")?S({},e.FORBID_CONTENTS,lt):qe,Ce=E(e,"FORBID_TAGS")?S({},e.FORBID_TAGS,lt):{},Le=E(e,"FORBID_ATTR")?S({},e.FORBID_ATTR,lt):{},je=!!E(e,"USE_PROFILES")&&e.USE_PROFILES,De=!1!==e.ALLOW_ARIA_ATTR,ve=!1!==e.ALLOW_DATA_ATTR,Oe=e.ALLOW_UNKNOWN_PROTOCOLS||!1,xe=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,ke=e.SAFE_FOR_TEMPLATES||!1,Me=!1!==e.SAFE_FOR_XML,Ie=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,He=e.RETURN_DOM_FRAGMENT||!1,ze=e.RETURN_TRUSTED_TYPE||!1,Pe=e.FORCE_BODY||!1,Be=!1!==e.SANITIZE_DOM,We=e.SANITIZE_NAMED_PROPS||!1,Ge=!1!==e.KEEP_CONTENT,Ye=e.IN_PLACE||!1,Ae=e.ALLOWED_URI_REGEXP||Y,tt=e.NAMESPACE||et,we=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(we.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(we.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(we.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ke&&(ve=!1),He&&(Fe=!0),je&&(Ne=S({},M),Se=[],!0===je.html&&(S(Ne,L),S(Se,I)),!0===je.svg&&(S(Ne,D),S(Se,U),S(Se,F)),!0===je.svgFilters&&(S(Ne,v),S(Se,U),S(Se,F)),!0===je.mathMl&&(S(Ne,x),S(Se,P),S(Se,F))),e.ADD_TAGS&&(Ne===be&&(Ne=w(Ne)),S(Ne,e.ADD_TAGS,lt)),e.ADD_ATTR&&(Se===Re&&(Se=w(Se)),S(Se,e.ADD_ATTR,lt)),e.ADD_URI_SAFE_ATTR&&S(Ve,e.ADD_URI_SAFE_ATTR,lt),e.FORBID_CONTENTS&&(Xe===qe&&(Xe=w(Xe)),S(Xe,e.FORBID_CONTENTS,lt)),Ge&&(Ne["#text"]=!0),Ie&&S(Ne,["html","head","body"]),Ne.table&&(S(Ne,["tbody"]),delete Ce.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ie=e.TRUSTED_TYPES_POLICY,ae=ie.createHTML("")}else void 0===ie&&(ie=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(G,c)),null!==ie&&"string"==typeof ae&&(ae=ie.createHTML(""));i&&i(e),ct=e}},pt=S({},["mi","mo","mn","ms","mtext"]),ft=S({},["foreignobject","annotation-xml"]),dt=S({},["title","style","font","a","script"]),ht=S({},[...D,...v,...O]),gt=S({},[...x,...k]),Tt=function(e){p(o.removed,{element:e});try{re(e).removeChild(e)}catch(t){$(e)}},yt=function(e,t){try{p(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Se[e])if(Fe||He)try{Tt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Et=function(e){let t=null,n=null;if(Pe)e=""+e;else{const t=h(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===it&&tt===et&&(e=''+e+"");const o=ie?ie.createHTML(e):e;if(tt===et)try{t=(new W).parseFromString(o,it)}catch(e){}if(!t||!t.documentElement){t=le.createDocument(tt,"template",null);try{t.documentElement.innerHTML=nt?ae:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),tt===et?ue.call(t,Ie?"html":"body")[0]:Ie?t.documentElement:i},_t=function(e){return ce.call(e.ownerDocument||e,e,H.SHOW_ELEMENT|H.SHOW_COMMENT|H.SHOW_TEXT|H.SHOW_PROCESSING_INSTRUCTION|H.SHOW_CDATA_SECTION,null)},At=function(e){return e instanceof B&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof z)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof b&&e instanceof b},bt=function(e,t,n){pe[e]&&u(pe[e],(e=>{e.call(o,t,n,ct)}))},St=function(e){let t=null;if(bt("beforeSanitizeElements",e,null),At(e))return Tt(e),!0;const n=lt(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ne}),e.hasChildNodes()&&!Nt(e.firstElementChild)&&_(/<[/\w]/g,e.innerHTML)&&_(/<[/\w]/g,e.textContent))return Tt(e),!0;if(e.nodeType===J)return Tt(e),!0;if(Me&&e.nodeType===Q&&_(/<[/\w]/g,e.data))return Tt(e),!0;if(!Ne[n]||Ce[n]){if(!Ce[n]&&wt(n)){if(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n))return!1;if(we.tagNameCheck instanceof Function&&we.tagNameCheck(n))return!1}if(Ge&&!Xe[n]){const t=re(e)||e.parentNode,n=oe(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=X(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,ne(e))}}}return Tt(e),!0}return e instanceof R&&!function(e){let t=re(e);t&&t.tagName||(t={namespaceURI:tt,tagName:"template"});const n=f(e.tagName),o=f(t.tagName);return!!ot[e.namespaceURI]&&(e.namespaceURI===Qe?t.namespaceURI===et?"svg"===n:t.namespaceURI===Je?"svg"===n&&("annotation-xml"===o||pt[o]):Boolean(ht[n]):e.namespaceURI===Je?t.namespaceURI===et?"math"===n:t.namespaceURI===Qe?"math"===n&&ft[o]:Boolean(gt[n]):e.namespaceURI===et?!(t.namespaceURI===Qe&&!ft[o])&&!(t.namespaceURI===Je&&!pt[o])&&!gt[n]&&(dt[n]||!ht[n]):!("application/xhtml+xml"!==it||!ot[e.namespaceURI]))}(e)?(Tt(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!_(/<\/no(script|embed|frames)/i,e.innerHTML)?(ke&&e.nodeType===Z&&(t=e.textContent,u([fe,de,he],(e=>{t=g(t,e," ")})),e.textContent!==t&&(p(o.removed,{element:e.cloneNode()}),e.textContent=t)),bt("afterSanitizeElements",e,null),!1):(Tt(e),!0)},Rt=function(e,t,n){if(Be&&("id"===t||"name"===t)&&(n in r||n in st))return!1;if(ve&&!Le[t]&&_(ge,t));else if(De&&_(Te,t));else if(!Se[t]||Le[t]){if(!(wt(e)&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,e)||we.tagNameCheck instanceof Function&&we.tagNameCheck(e))&&(we.attributeNameCheck instanceof RegExp&&_(we.attributeNameCheck,t)||we.attributeNameCheck instanceof Function&&we.attributeNameCheck(t))||"is"===t&&we.allowCustomizedBuiltInElements&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n)||we.tagNameCheck instanceof Function&&we.tagNameCheck(n))))return!1}else if(Ve[t]);else if(_(Ae,g(n,Ee,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==T(n,"data:")||!$e[e]){if(Oe&&!_(ye,g(n,Ee,"")));else if(n)return!1}else;return!0},wt=function(e){return"annotation-xml"!==e&&h(e,_e)},Ct=function(e){bt("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Se};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=lt(a);let p="value"===a?c:y(c);if(n.attrName=s,n.attrValue=p,n.keepAttr=!0,n.forceKeepAttr=void 0,bt("uponSanitizeAttribute",e,n),p=n.attrValue,Me&&_(/((--!?|])>)|<\/(style|title)/i,p)){yt(a,e);continue}if(n.forceKeepAttr)continue;if(yt(a,e),!n.keepAttr)continue;if(!xe&&_(/\/>/i,p)){yt(a,e);continue}ke&&u([fe,de,he],(e=>{p=g(p,e," ")}));const f=lt(e.nodeName);if(Rt(f,s,p)){if(!We||"id"!==s&&"name"!==s||(yt(a,e),p="user-content-"+p),ie&&"object"==typeof G&&"function"==typeof G.getAttributeType)if(l);else switch(G.getAttributeType(f,s)){case"TrustedHTML":p=ie.createHTML(p);break;case"TrustedScriptURL":p=ie.createScriptURL(p)}try{l?e.setAttributeNS(l,a,p):e.setAttribute(a,p),At(e)?Tt(e):m(o.removed)}catch(e){}}}bt("afterSanitizeAttributes",e,null)},Lt=function e(t){let n=null;const o=_t(t);for(bt("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)bt("uponSanitizeShadowNode",n,null),St(n)||(n.content instanceof s&&e(n.content),Ct(n));bt("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(nt=!e,nt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw A("toString is not a function");if("string"!=typeof(e=e.toString()))throw A("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Ue||mt(t),o.removed=[],"string"==typeof e&&(Ye=!1),Ye){if(e.nodeName){const t=lt(e.nodeName);if(!Ne[t]||Ce[t])throw A("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof b)n=Et("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===V&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!ke&&!Ie&&-1===e.indexOf("<"))return ie&&ze?ie.createHTML(e):e;if(n=Et(e),!n)return Fe?null:ze?ae:""}n&&Pe&&Tt(n.firstChild);const c=_t(Ye?e:n);for(;i=c.nextNode();)St(i)||(i.content instanceof s&&Lt(i.content),Ct(i));if(Ye)return e;if(Fe){if(He)for(l=se.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Se.shadowroot||Se.shadowrootmode)&&(l=me.call(a,l,!0)),l}let m=Ie?n.outerHTML:n.innerHTML;return Ie&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&_(q,n.ownerDocument.doctype.name)&&(m="\n"+m),ke&&u([fe,de,he],(e=>{m=g(m,e," ")})),ie&&ze?ie.createHTML(m):m},o.setConfig=function(){mt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Ue=!0},o.clearConfig=function(){ct=null,Ue=!1},o.isValidAttribute=function(e,t,n){ct||mt({});const o=lt(e),r=lt(t);return Rt(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&(pe[e]=pe[e]||[],p(pe[e],t))},o.removeHook=function(e){if(pe[e])return m(pe[e])},o.removeHooks=function(e){pe[e]&&(pe[e]=[])},o.removeAllHooks=function(){pe={}},o}();return ne})); +//# sourceMappingURL=purify.min.js.map diff --git a/public/scripts/purify.js b/public/scripts/purify.js new file mode 100644 index 00000000..b61a960b --- /dev/null +++ b/public/scripts/purify.js @@ -0,0 +1,1563 @@ +/*! @license DOMPurify 3.1.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.6/LICENSE */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DOMPurify = factory()); + })(this, (function () { 'use strict'; + + const { + entries, + setPrototypeOf, + isFrozen, + getPrototypeOf, + getOwnPropertyDescriptor + } = Object; + let { + freeze, + seal, + create + } = Object; // eslint-disable-line import/no-mutable-exports + let { + apply, + construct + } = typeof Reflect !== 'undefined' && Reflect; + if (!freeze) { + freeze = function freeze(x) { + return x; + }; + } + if (!seal) { + seal = function seal(x) { + return x; + }; + } + if (!apply) { + apply = function apply(fun, thisValue, args) { + return fun.apply(thisValue, args); + }; + } + if (!construct) { + construct = function construct(Func, args) { + return new Func(...args); + }; + } + const arrayForEach = unapply(Array.prototype.forEach); + const arrayPop = unapply(Array.prototype.pop); + const arrayPush = unapply(Array.prototype.push); + const stringToLowerCase = unapply(String.prototype.toLowerCase); + const stringToString = unapply(String.prototype.toString); + const stringMatch = unapply(String.prototype.match); + const stringReplace = unapply(String.prototype.replace); + const stringIndexOf = unapply(String.prototype.indexOf); + const stringTrim = unapply(String.prototype.trim); + const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); + const regExpTest = unapply(RegExp.prototype.test); + const typeErrorCreate = unconstruct(TypeError); + + /** + * Creates a new function that calls the given function with a specified thisArg and arguments. + * + * @param {Function} func - The function to be wrapped and called. + * @returns {Function} A new function that calls the given function with a specified thisArg and arguments. + */ + function unapply(func) { + return function (thisArg) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + return apply(func, thisArg, args); + }; + } + + /** + * Creates a new function that constructs an instance of the given constructor function with the provided arguments. + * + * @param {Function} func - The constructor function to be wrapped and called. + * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments. + */ + function unconstruct(func) { + return function () { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + return construct(func, args); + }; + } + + /** + * Add properties to a lookup table + * + * @param {Object} set - The set to which elements will be added. + * @param {Array} array - The array containing elements to be added to the set. + * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set. + * @returns {Object} The modified set with added elements. + */ + function addToSet(set, array) { + let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase; + if (setPrototypeOf) { + // Make 'in' and truthy checks like Boolean(set.constructor) + // independent of any properties defined on Object.prototype. + // Prevent prototype setters from intercepting set as a this value. + setPrototypeOf(set, null); + } + let l = array.length; + while (l--) { + let element = array[l]; + if (typeof element === 'string') { + const lcElement = transformCaseFunc(element); + if (lcElement !== element) { + // Config presets (e.g. tags.js, attrs.js) are immutable. + if (!isFrozen(array)) { + array[l] = lcElement; + } + element = lcElement; + } + } + set[element] = true; + } + return set; + } + + /** + * Clean up an array to harden against CSPP + * + * @param {Array} array - The array to be cleaned. + * @returns {Array} The cleaned version of the array + */ + function cleanArray(array) { + for (let index = 0; index < array.length; index++) { + const isPropertyExist = objectHasOwnProperty(array, index); + if (!isPropertyExist) { + array[index] = null; + } + } + return array; + } + + /** + * Shallow clone an object + * + * @param {Object} object - The object to be cloned. + * @returns {Object} A new object that copies the original. + */ + function clone(object) { + const newObject = create(null); + for (const [property, value] of entries(object)) { + const isPropertyExist = objectHasOwnProperty(object, property); + if (isPropertyExist) { + if (Array.isArray(value)) { + newObject[property] = cleanArray(value); + } else if (value && typeof value === 'object' && value.constructor === Object) { + newObject[property] = clone(value); + } else { + newObject[property] = value; + } + } + } + return newObject; + } + + /** + * This method automatically checks if the prop is function or getter and behaves accordingly. + * + * @param {Object} object - The object to look up the getter function in its prototype chain. + * @param {String} prop - The property name for which to find the getter function. + * @returns {Function} The getter function found in the prototype chain or a fallback function. + */ + function lookupGetter(object, prop) { + while (object !== null) { + const desc = getOwnPropertyDescriptor(object, prop); + if (desc) { + if (desc.get) { + return unapply(desc.get); + } + if (typeof desc.value === 'function') { + return unapply(desc.value); + } + } + object = getPrototypeOf(object); + } + function fallbackValue() { + return null; + } + return fallbackValue; + } + + const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']); + + // SVG + const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']); + const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); + + // List of SVG elements that are disallowed by default. + // We still need to know them so that we can do namespace + // checks properly in case one wants to add them to + // allow-list. + const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']); + const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']); + + // Similarly to SVG, we want to know all MathML elements, + // even those that we disallow by default. + const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']); + const text = freeze(['#text']); + + const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']); + const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']); + const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']); + const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']); + + // eslint-disable-next-line unicorn/better-regex + const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode + const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm); + const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm); + const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape + const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape + const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape + ); + const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); + const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex + ); + const DOCTYPE_NAME = seal(/^html$/i); + const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); + + var EXPRESSIONS = /*#__PURE__*/Object.freeze({ + __proto__: null, + MUSTACHE_EXPR: MUSTACHE_EXPR, + ERB_EXPR: ERB_EXPR, + TMPLIT_EXPR: TMPLIT_EXPR, + DATA_ATTR: DATA_ATTR, + ARIA_ATTR: ARIA_ATTR, + IS_ALLOWED_URI: IS_ALLOWED_URI, + IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA, + ATTR_WHITESPACE: ATTR_WHITESPACE, + DOCTYPE_NAME: DOCTYPE_NAME, + CUSTOM_ELEMENT: CUSTOM_ELEMENT + }); + + // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType + const NODE_TYPE = { + element: 1, + attribute: 2, + text: 3, + cdataSection: 4, + entityReference: 5, + // Deprecated + entityNode: 6, + // Deprecated + progressingInstruction: 7, + comment: 8, + document: 9, + documentType: 10, + documentFragment: 11, + notation: 12 // Deprecated + }; + const getGlobal = function getGlobal() { + return typeof window === 'undefined' ? null : window; + }; + + /** + * Creates a no-op policy for internal use only. + * Don't export this function outside this module! + * @param {TrustedTypePolicyFactory} trustedTypes The policy factory. + * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix). + * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types + * are not supported or creating the policy failed). + */ + const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) { + if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') { + return null; + } + + // Allow the callers to control the unique policy name + // by adding a data-tt-policy-suffix to the script element with the DOMPurify. + // Policy creation with duplicate names throws in Trusted Types. + let suffix = null; + const ATTR_NAME = 'data-tt-policy-suffix'; + if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) { + suffix = purifyHostElement.getAttribute(ATTR_NAME); + } + const policyName = 'dompurify' + (suffix ? '#' + suffix : ''); + try { + return trustedTypes.createPolicy(policyName, { + createHTML(html) { + return html; + }, + createScriptURL(scriptUrl) { + return scriptUrl; + } + }); + } catch (_) { + // Policy creation failed (most likely another DOMPurify script has + // already run). Skip creating the policy, as this will only cause errors + // if TT are enforced. + console.warn('TrustedTypes policy ' + policyName + ' could not be created.'); + return null; + } + }; + function createDOMPurify() { + let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); + const DOMPurify = root => createDOMPurify(root); + + /** + * Version label, exposed for easier checks + * if DOMPurify is up to date or not + */ + DOMPurify.version = '3.1.6'; + + /** + * Array of elements that DOMPurify removed during sanitation. + * Empty if nothing was removed. + */ + DOMPurify.removed = []; + if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) { + // Not running in a browser, provide a factory function + // so that you can pass your own Window + DOMPurify.isSupported = false; + return DOMPurify; + } + let { + document + } = window; + const originalDocument = document; + const currentScript = originalDocument.currentScript; + const { + DocumentFragment, + HTMLTemplateElement, + Node, + Element, + NodeFilter, + NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap, + HTMLFormElement, + DOMParser, + trustedTypes + } = window; + const ElementPrototype = Element.prototype; + const cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); + const remove = lookupGetter(ElementPrototype, 'remove'); + const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); + const getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); + const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + + // As per issue #47, the web-components registry is inherited by a + // new document created via createHTMLDocument. As per the spec + // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) + // a new empty registry is used when creating a template contents owner + // document, so we use that as our parent document to ensure nothing + // is inherited. + if (typeof HTMLTemplateElement === 'function') { + const template = document.createElement('template'); + if (template.content && template.content.ownerDocument) { + document = template.content.ownerDocument; + } + } + let trustedTypesPolicy; + let emptyHTML = ''; + const { + implementation, + createNodeIterator, + createDocumentFragment, + getElementsByTagName + } = document; + const { + importNode + } = originalDocument; + let hooks = {}; + + /** + * Expose whether this browser supports running the full DOMPurify. + */ + DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined; + const { + MUSTACHE_EXPR, + ERB_EXPR, + TMPLIT_EXPR, + DATA_ATTR, + ARIA_ATTR, + IS_SCRIPT_OR_DATA, + ATTR_WHITESPACE, + CUSTOM_ELEMENT + } = EXPRESSIONS; + let { + IS_ALLOWED_URI: IS_ALLOWED_URI$1 + } = EXPRESSIONS; + + /** + * We consider the elements and attributes below to be safe. Ideally + * don't add any new ones but feel free to remove unwanted ones. + */ + + /* allowed element names */ + let ALLOWED_TAGS = null; + const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]); + + /* Allowed attribute names */ + let ALLOWED_ATTR = null; + const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]); + + /* + * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements. + * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements) + * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list) + * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`. + */ + let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, { + tagNameCheck: { + writable: true, + configurable: false, + enumerable: true, + value: null + }, + attributeNameCheck: { + writable: true, + configurable: false, + enumerable: true, + value: null + }, + allowCustomizedBuiltInElements: { + writable: true, + configurable: false, + enumerable: true, + value: false + } + })); + + /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ + let FORBID_TAGS = null; + + /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ + let FORBID_ATTR = null; + + /* Decide if ARIA attributes are okay */ + let ALLOW_ARIA_ATTR = true; + + /* Decide if custom data attributes are okay */ + let ALLOW_DATA_ATTR = true; + + /* Decide if unknown protocols are okay */ + let ALLOW_UNKNOWN_PROTOCOLS = false; + + /* Decide if self-closing tags in attributes are allowed. + * Usually removed due to a mXSS issue in jQuery 3.0 */ + let ALLOW_SELF_CLOSE_IN_ATTR = true; + + /* Output should be safe for common template engines. + * This means, DOMPurify removes data attributes, mustaches and ERB + */ + let SAFE_FOR_TEMPLATES = false; + + /* Output should be safe even for XML used within HTML and alike. + * This means, DOMPurify removes comments when containing risky content. + */ + let SAFE_FOR_XML = true; + + /* Decide if document with ... should be returned */ + let WHOLE_DOCUMENT = false; + + /* Track whether config is already set on this instance of DOMPurify. */ + let SET_CONFIG = false; + + /* Decide if all elements (e.g. style, script) must be children of + * document.body. By default, browsers might move them to document.head */ + let FORCE_BODY = false; + + /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html + * string (or a TrustedHTML object if Trusted Types are supported). + * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead + */ + let RETURN_DOM = false; + + /* Decide if a DOM `DocumentFragment` should be returned, instead of a html + * string (or a TrustedHTML object if Trusted Types are supported) */ + let RETURN_DOM_FRAGMENT = false; + + /* Try to return a Trusted Type object instead of a string, return a string in + * case Trusted Types are not supported */ + let RETURN_TRUSTED_TYPE = false; + + /* Output should be free from DOM clobbering attacks? + * This sanitizes markups named with colliding, clobberable built-in DOM APIs. + */ + let SANITIZE_DOM = true; + + /* Achieve full DOM Clobbering protection by isolating the namespace of named + * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules. + * + * HTML/DOM spec rules that enable DOM Clobbering: + * - Named Access on Window (§7.3.3) + * - DOM Tree Accessors (§3.1.5) + * - Form Element Parent-Child Relations (§4.10.3) + * - Iframe srcdoc / Nested WindowProxies (§4.8.5) + * - HTMLCollection (§4.2.10.2) + * + * Namespace isolation is implemented by prefixing `id` and `name` attributes + * with a constant string, i.e., `user-content-` + */ + let SANITIZE_NAMED_PROPS = false; + const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-'; + + /* Keep element content when removing element? */ + let KEEP_CONTENT = true; + + /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead + * of importing it into a new Document and returning a sanitized copy */ + let IN_PLACE = false; + + /* Allow usage of profiles like html, svg and mathMl */ + let USE_PROFILES = {}; + + /* Tags to ignore content of when KEEP_CONTENT is true */ + let FORBID_CONTENTS = null; + const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']); + + /* Tags that are safe for data: URIs */ + let DATA_URI_TAGS = null; + const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']); + + /* Attributes safe for values like "javascript:" */ + let URI_SAFE_ATTRIBUTES = null; + const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']); + const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; + const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; + const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; + /* Document namespace */ + let NAMESPACE = HTML_NAMESPACE; + let IS_EMPTY_INPUT = false; + + /* Allowed XHTML+XML namespaces */ + let ALLOWED_NAMESPACES = null; + const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString); + + /* Parsing of strict XHTML documents */ + let PARSER_MEDIA_TYPE = null; + const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html']; + const DEFAULT_PARSER_MEDIA_TYPE = 'text/html'; + let transformCaseFunc = null; + + /* Keep a reference to config to pass to hooks */ + let CONFIG = null; + + /* Ideally, do not touch anything below this line */ + /* ______________________________________________ */ + + const formElement = document.createElement('form'); + const isRegexOrFunction = function isRegexOrFunction(testValue) { + return testValue instanceof RegExp || testValue instanceof Function; + }; + + /** + * _parseConfig + * + * @param {Object} cfg optional config literal + */ + // eslint-disable-next-line complexity + const _parseConfig = function _parseConfig() { + let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + if (CONFIG && CONFIG === cfg) { + return; + } + + /* Shield configuration object from tampering */ + if (!cfg || typeof cfg !== 'object') { + cfg = {}; + } + + /* Shield configuration object from prototype pollution */ + cfg = clone(cfg); + PARSER_MEDIA_TYPE = + // eslint-disable-next-line unicorn/prefer-includes + SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE; + + // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is. + transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase; + + /* Set configuration parameters */ + ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR; + ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES; + URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), + // eslint-disable-line indent + cfg.ADD_URI_SAFE_ATTR, + // eslint-disable-line indent + transformCaseFunc // eslint-disable-line indent + ) // eslint-disable-line indent + : DEFAULT_URI_SAFE_ATTRIBUTES; + DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), + // eslint-disable-line indent + cfg.ADD_DATA_URI_TAGS, + // eslint-disable-line indent + transformCaseFunc // eslint-disable-line indent + ) // eslint-disable-line indent + : DEFAULT_DATA_URI_TAGS; + FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS; + FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {}; + FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {}; + USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false; + ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true + ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false + ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true + SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false + SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false + RETURN_DOM = cfg.RETURN_DOM || false; // Default false + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false + RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false + FORCE_BODY = cfg.FORCE_BODY || false; // Default false + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true + SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true + IN_PLACE = cfg.IN_PLACE || false; // Default false + IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI; + NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE; + CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {}; + if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) { + CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck; + } + if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) { + CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck; + } + if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') { + CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements; + } + if (SAFE_FOR_TEMPLATES) { + ALLOW_DATA_ATTR = false; + } + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + + /* Parse profile info */ + if (USE_PROFILES) { + ALLOWED_TAGS = addToSet({}, text); + ALLOWED_ATTR = []; + if (USE_PROFILES.html === true) { + addToSet(ALLOWED_TAGS, html$1); + addToSet(ALLOWED_ATTR, html); + } + if (USE_PROFILES.svg === true) { + addToSet(ALLOWED_TAGS, svg$1); + addToSet(ALLOWED_ATTR, svg); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.svgFilters === true) { + addToSet(ALLOWED_TAGS, svgFilters); + addToSet(ALLOWED_ATTR, svg); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.mathMl === true) { + addToSet(ALLOWED_TAGS, mathMl$1); + addToSet(ALLOWED_ATTR, mathMl); + addToSet(ALLOWED_ATTR, xml); + } + } + + /* Merge configuration parameters */ + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = clone(ALLOWED_TAGS); + } + addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); + } + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = clone(ALLOWED_ATTR); + } + addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); + } + if (cfg.ADD_URI_SAFE_ATTR) { + addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); + } + if (cfg.FORBID_CONTENTS) { + if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { + FORBID_CONTENTS = clone(FORBID_CONTENTS); + } + addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); + } + + /* Add #text in case KEEP_CONTENT is set to true */ + if (KEEP_CONTENT) { + ALLOWED_TAGS['#text'] = true; + } + + /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */ + if (WHOLE_DOCUMENT) { + addToSet(ALLOWED_TAGS, ['html', 'head', 'body']); + } + + /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */ + if (ALLOWED_TAGS.table) { + addToSet(ALLOWED_TAGS, ['tbody']); + delete FORBID_TAGS.tbody; + } + if (cfg.TRUSTED_TYPES_POLICY) { + if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') { + throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.'); + } + if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') { + throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.'); + } + + // Overwrite existing TrustedTypes policy. + trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; + + // Sign local variables required by `sanitize`. + emptyHTML = trustedTypesPolicy.createHTML(''); + } else { + // Uninitialized policy, attempt to initialize the internal dompurify policy. + if (trustedTypesPolicy === undefined) { + trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); + } + + // If creating the internal policy succeeded sign internal variables. + if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') { + emptyHTML = trustedTypesPolicy.createHTML(''); + } + } + + // Prevent further manipulation of configuration. + // Not available in IE8, Safari 5, etc. + if (freeze) { + freeze(cfg); + } + CONFIG = cfg; + }; + const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']); + const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']); + + // Certain elements are allowed in both SVG and HTML + // namespace. We need to specify them explicitly + // so that they don't get erroneously deleted from + // HTML namespace. + const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']); + + /* Keep track of all possible SVG and MathML tags + * so that we can perform the namespace checks + * correctly. */ + const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]); + const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]); + + /** + * @param {Element} element a DOM element whose namespace is being checked + * @returns {boolean} Return false if the element has a + * namespace that a spec-compliant parser would never + * return. Return true otherwise. + */ + const _checkValidNamespace = function _checkValidNamespace(element) { + let parent = getParentNode(element); + + // In JSDOM, if we're inside shadow DOM, then parentNode + // can be null. We just simulate parent in this case. + if (!parent || !parent.tagName) { + parent = { + namespaceURI: NAMESPACE, + tagName: 'template' + }; + } + const tagName = stringToLowerCase(element.tagName); + const parentTagName = stringToLowerCase(parent.tagName); + if (!ALLOWED_NAMESPACES[element.namespaceURI]) { + return false; + } + if (element.namespaceURI === SVG_NAMESPACE) { + // The only way to switch from HTML namespace to SVG + // is via . If it happens via any other tag, then + // it should be killed. + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === 'svg'; + } + + // The only way to switch from MathML to SVG is via` + // svg if parent is either or MathML + // text integration points. + if (parent.namespaceURI === MATHML_NAMESPACE) { + return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); + } + + // We only allow elements that are defined in SVG + // spec. All others are disallowed in SVG namespace. + return Boolean(ALL_SVG_TAGS[tagName]); + } + if (element.namespaceURI === MATHML_NAMESPACE) { + // The only way to switch from HTML namespace to MathML + // is via . If it happens via any other tag, then + // it should be killed. + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === 'math'; + } + + // The only way to switch from SVG to MathML is via + // and HTML integration points + if (parent.namespaceURI === SVG_NAMESPACE) { + return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName]; + } + + // We only allow elements that are defined in MathML + // spec. All others are disallowed in MathML namespace. + return Boolean(ALL_MATHML_TAGS[tagName]); + } + if (element.namespaceURI === HTML_NAMESPACE) { + // The only way to switch from SVG to HTML is via + // HTML integration points, and from MathML to HTML + // is via MathML text integration points + if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { + return false; + } + if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { + return false; + } + + // We disallow tags that are specific for MathML + // or SVG and should never appear in HTML namespace + return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); + } + + // For XHTML and XML documents that support custom namespaces + if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) { + return true; + } + + // The code should never reach this place (this means + // that the element somehow got namespace that is not + // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES). + // Return false just in case. + return false; + }; + + /** + * _forceRemove + * + * @param {Node} node a DOM node + */ + const _forceRemove = function _forceRemove(node) { + arrayPush(DOMPurify.removed, { + element: node + }); + try { + // eslint-disable-next-line unicorn/prefer-dom-node-remove + getParentNode(node).removeChild(node); + } catch (_) { + remove(node); + } + }; + + /** + * _removeAttribute + * + * @param {String} name an Attribute name + * @param {Node} node a DOM node + */ + const _removeAttribute = function _removeAttribute(name, node) { + try { + arrayPush(DOMPurify.removed, { + attribute: node.getAttributeNode(name), + from: node + }); + } catch (_) { + arrayPush(DOMPurify.removed, { + attribute: null, + from: node + }); + } + node.removeAttribute(name); + + // We void attribute values for unremovable "is"" attributes + if (name === 'is' && !ALLOWED_ATTR[name]) { + if (RETURN_DOM || RETURN_DOM_FRAGMENT) { + try { + _forceRemove(node); + } catch (_) {} + } else { + try { + node.setAttribute(name, ''); + } catch (_) {} + } + } + }; + + /** + * _initDocument + * + * @param {String} dirty a string of dirty markup + * @return {Document} a DOM, filled with the dirty markup + */ + const _initDocument = function _initDocument(dirty) { + /* Create a HTML document */ + let doc = null; + let leadingWhitespace = null; + if (FORCE_BODY) { + dirty = '' + dirty; + } else { + /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */ + const matches = stringMatch(dirty, /^[\r\n\t ]+/); + leadingWhitespace = matches && matches[0]; + } + if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) { + // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict) + dirty = '' + dirty + ''; + } + const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty; + /* + * Use the DOMParser API by default, fallback later if needs be + * DOMParser not work for svg when has multiple root element. + */ + if (NAMESPACE === HTML_NAMESPACE) { + try { + doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); + } catch (_) {} + } + + /* Use createHTMLDocument in case DOMParser is not available */ + if (!doc || !doc.documentElement) { + doc = implementation.createDocument(NAMESPACE, 'template', null); + try { + doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload; + } catch (_) { + // Syntax error if dirtyPayload is invalid xml + } + } + const body = doc.body || doc.documentElement; + if (dirty && leadingWhitespace) { + body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null); + } + + /* Work on whole document or just its body */ + if (NAMESPACE === HTML_NAMESPACE) { + return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0]; + } + return WHOLE_DOCUMENT ? doc.documentElement : body; + }; + + /** + * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. + * + * @param {Node} root The root element or node to start traversing on. + * @return {NodeIterator} The created NodeIterator + */ + const _createNodeIterator = function _createNodeIterator(root) { + return createNodeIterator.call(root.ownerDocument || root, root, + // eslint-disable-next-line no-bitwise + NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null); + }; + + /** + * _isClobbered + * + * @param {Node} elm element to check for clobbering attacks + * @return {Boolean} true if clobbered, false if safe + */ + const _isClobbered = function _isClobbered(elm) { + return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function'); + }; + + /** + * Checks whether the given object is a DOM node. + * + * @param {Node} object object to check whether it's a DOM node + * @return {Boolean} true is object is a DOM node + */ + const _isNode = function _isNode(object) { + return typeof Node === 'function' && object instanceof Node; + }; + + /** + * _executeHook + * Execute user configurable hooks + * + * @param {String} entryPoint Name of the hook's entry point + * @param {Node} currentNode node to work on with the hook + * @param {Object} data additional hook parameters + */ + const _executeHook = function _executeHook(entryPoint, currentNode, data) { + if (!hooks[entryPoint]) { + return; + } + arrayForEach(hooks[entryPoint], hook => { + hook.call(DOMPurify, currentNode, data, CONFIG); + }); + }; + + /** + * _sanitizeElements + * + * @protect nodeName + * @protect textContent + * @protect removeChild + * + * @param {Node} currentNode to check for permission to exist + * @return {Boolean} true if node was killed, false if left alive + */ + const _sanitizeElements = function _sanitizeElements(currentNode) { + let content = null; + + /* Execute a hook if present */ + _executeHook('beforeSanitizeElements', currentNode, null); + + /* Check if element is clobbered or can clobber */ + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + + /* Now let's check the element's type and name */ + const tagName = transformCaseFunc(currentNode.nodeName); + + /* Execute a hook if present */ + _executeHook('uponSanitizeElement', currentNode, { + tagName, + allowedTags: ALLOWED_TAGS + }); + + /* Detect mXSS attempts abusing namespace confusion */ + if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) { + _forceRemove(currentNode); + return true; + } + + /* Remove any occurrence of processing instructions */ + if (currentNode.nodeType === NODE_TYPE.progressingInstruction) { + _forceRemove(currentNode); + return true; + } + + /* Remove any kind of possibly harmful comments */ + if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) { + _forceRemove(currentNode); + return true; + } + + /* Remove element if anything forbids its presence */ + if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { + /* Check if we have a custom element to handle */ + if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) { + if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) { + return false; + } + if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) { + return false; + } + } + + /* Keep content except for bad-listed elements */ + if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { + const parentNode = getParentNode(currentNode) || currentNode.parentNode; + const childNodes = getChildNodes(currentNode) || currentNode.childNodes; + if (childNodes && parentNode) { + const childCount = childNodes.length; + for (let i = childCount - 1; i >= 0; --i) { + const childClone = cloneNode(childNodes[i], true); + childClone.__removalCount = (currentNode.__removalCount || 0) + 1; + parentNode.insertBefore(childClone, getNextSibling(currentNode)); + } + } + } + _forceRemove(currentNode); + return true; + } + + /* Check whether element has a valid namespace */ + if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { + _forceRemove(currentNode); + return true; + } + + /* Make sure that older browsers don't get fallback-tag mXSS */ + if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) { + _forceRemove(currentNode); + return true; + } + + /* Sanitize element content to be template-safe */ + if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { + /* Get the element's text content */ + content = currentNode.textContent; + arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => { + content = stringReplace(content, expr, ' '); + }); + if (currentNode.textContent !== content) { + arrayPush(DOMPurify.removed, { + element: currentNode.cloneNode() + }); + currentNode.textContent = content; + } + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeElements', currentNode, null); + return false; + }; + + /** + * _isValidAttribute + * + * @param {string} lcTag Lowercase tag name of containing element. + * @param {string} lcName Lowercase attribute name. + * @param {string} value Attribute value. + * @return {Boolean} Returns true if `value` is valid, otherwise false. + */ + // eslint-disable-next-line complexity + const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { + /* Make sure attribute cannot clobber */ + if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) { + return false; + } + + /* Allow valid data-* attributes: At least one character after "-" + (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) + XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) + We don't need to check the value; it's always URI safe. */ + if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) { + if ( + // First condition does a very basic check if a) it's basically a valid custom element tagname AND + // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck + // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck + _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || + // Alternative, second condition checks if it's an `is`-attribute, AND + // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck + lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else { + return false; + } + /* Check value is safe. First, is attr inert? If so, is safe */ + } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) { + return false; + } else ; + return true; + }; + + /** + * _isBasicCustomElement + * checks if at least one dash is included in tagName, and it's not the first char + * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name + * + * @param {string} tagName name of the tag of the node to sanitize + * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false. + */ + const _isBasicCustomElement = function _isBasicCustomElement(tagName) { + return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT); + }; + + /** + * _sanitizeAttributes + * + * @protect attributes + * @protect nodeName + * @protect removeAttribute + * @protect setAttribute + * + * @param {Node} currentNode to sanitize + */ + const _sanitizeAttributes = function _sanitizeAttributes(currentNode) { + /* Execute a hook if present */ + _executeHook('beforeSanitizeAttributes', currentNode, null); + const { + attributes + } = currentNode; + + /* Check if we have attributes; if not we might have a text node */ + if (!attributes) { + return; + } + const hookEvent = { + attrName: '', + attrValue: '', + keepAttr: true, + allowedAttributes: ALLOWED_ATTR + }; + let l = attributes.length; + + /* Go backwards over all attributes; safely remove bad ones */ + while (l--) { + const attr = attributes[l]; + const { + name, + namespaceURI, + value: attrValue + } = attr; + const lcName = transformCaseFunc(name); + let value = name === 'value' ? attrValue : stringTrim(attrValue); + + /* Execute a hook if present */ + hookEvent.attrName = lcName; + hookEvent.attrValue = value; + hookEvent.keepAttr = true; + hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set + _executeHook('uponSanitizeAttribute', currentNode, hookEvent); + value = hookEvent.attrValue; + + /* Work around a security issue with comments inside attributes */ + if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) { + _removeAttribute(name, currentNode); + continue; + } + + /* Did the hooks approve of the attribute? */ + if (hookEvent.forceKeepAttr) { + continue; + } + + /* Remove attribute */ + _removeAttribute(name, currentNode); + + /* Did the hooks approve of the attribute? */ + if (!hookEvent.keepAttr) { + continue; + } + + /* Work around a security issue in jQuery 3.0 */ + if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) { + _removeAttribute(name, currentNode); + continue; + } + + /* Sanitize attribute content to be template-safe */ + if (SAFE_FOR_TEMPLATES) { + arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => { + value = stringReplace(value, expr, ' '); + }); + } + + /* Is `value` valid for this attribute? */ + const lcTag = transformCaseFunc(currentNode.nodeName); + if (!_isValidAttribute(lcTag, lcName, value)) { + continue; + } + + /* Full DOM Clobbering protection via namespace isolation, + * Prefix id and name attributes with `user-content-` + */ + if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) { + // Remove the attribute with this value + _removeAttribute(name, currentNode); + + // Prefix the value and later re-create the attribute with the sanitized value + value = SANITIZE_NAMED_PROPS_PREFIX + value; + } + + /* Handle attributes that require Trusted Types */ + if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') { + if (namespaceURI) ; else { + switch (trustedTypes.getAttributeType(lcTag, lcName)) { + case 'TrustedHTML': + { + value = trustedTypesPolicy.createHTML(value); + break; + } + case 'TrustedScriptURL': + { + value = trustedTypesPolicy.createScriptURL(value); + break; + } + } + } + } + + /* Handle invalid data-* attribute set by try-catching it */ + try { + if (namespaceURI) { + currentNode.setAttributeNS(namespaceURI, name, value); + } else { + /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */ + currentNode.setAttribute(name, value); + } + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + } else { + arrayPop(DOMPurify.removed); + } + } catch (_) {} + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeAttributes', currentNode, null); + }; + + /** + * _sanitizeShadowDOM + * + * @param {DocumentFragment} fragment to iterate over recursively + */ + const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) { + let shadowNode = null; + const shadowIterator = _createNodeIterator(fragment); + + /* Execute a hook if present */ + _executeHook('beforeSanitizeShadowDOM', fragment, null); + while (shadowNode = shadowIterator.nextNode()) { + /* Execute a hook if present */ + _executeHook('uponSanitizeShadowNode', shadowNode, null); + + /* Sanitize tags and elements */ + if (_sanitizeElements(shadowNode)) { + continue; + } + + /* Deep shadow DOM detected */ + if (shadowNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(shadowNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(shadowNode); + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeShadowDOM', fragment, null); + }; + + /** + * Sanitize + * Public method providing core sanitation functionality + * + * @param {String|Node} dirty string or DOM node + * @param {Object} cfg object + */ + // eslint-disable-next-line complexity + DOMPurify.sanitize = function (dirty) { + let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + let body = null; + let importedNode = null; + let currentNode = null; + let returnNode = null; + /* Make sure we have a string to sanitize. + DO NOT return early, as this will return the wrong type if + the user has requested a DOM object rather than a string */ + IS_EMPTY_INPUT = !dirty; + if (IS_EMPTY_INPUT) { + dirty = ''; + } + + /* Stringify, in case dirty is an object */ + if (typeof dirty !== 'string' && !_isNode(dirty)) { + if (typeof dirty.toString === 'function') { + dirty = dirty.toString(); + if (typeof dirty !== 'string') { + throw typeErrorCreate('dirty is not a string, aborting'); + } + } else { + throw typeErrorCreate('toString is not a function'); + } + } + + /* Return dirty HTML if DOMPurify cannot run */ + if (!DOMPurify.isSupported) { + return dirty; + } + + /* Assign config vars */ + if (!SET_CONFIG) { + _parseConfig(cfg); + } + + /* Clean up removed elements */ + DOMPurify.removed = []; + + /* Check if dirty is correctly typed for IN_PLACE */ + if (typeof dirty === 'string') { + IN_PLACE = false; + } + if (IN_PLACE) { + /* Do some early pre-sanitization to avoid unsafe root nodes */ + if (dirty.nodeName) { + const tagName = transformCaseFunc(dirty.nodeName); + if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { + throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place'); + } + } + } else if (dirty instanceof Node) { + /* If dirty is a DOM element, append to an empty document to avoid + elements being stripped by the parser */ + body = _initDocument(''); + importedNode = body.ownerDocument.importNode(dirty, true); + if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') { + /* Node is already a body, use as is */ + body = importedNode; + } else if (importedNode.nodeName === 'HTML') { + body = importedNode; + } else { + // eslint-disable-next-line unicorn/prefer-dom-node-append + body.appendChild(importedNode); + } + } else { + /* Exit directly if we have nothing to do */ + if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && + // eslint-disable-next-line unicorn/prefer-includes + dirty.indexOf('<') === -1) { + return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty; + } + + /* Initialize the document to work on */ + body = _initDocument(dirty); + + /* Check we have a DOM node from the data */ + if (!body) { + return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : ''; + } + } + + /* Remove first element node (ours) if FORCE_BODY is set */ + if (body && FORCE_BODY) { + _forceRemove(body.firstChild); + } + + /* Get node iterator */ + const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body); + + /* Now start iterating over the created document */ + while (currentNode = nodeIterator.nextNode()) { + /* Sanitize tags and elements */ + if (_sanitizeElements(currentNode)) { + continue; + } + + /* Shadow DOM detected, sanitize it */ + if (currentNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(currentNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(currentNode); + } + + /* If we sanitized `dirty` in-place, return it. */ + if (IN_PLACE) { + return dirty; + } + + /* Return sanitized string or DOM */ + if (RETURN_DOM) { + if (RETURN_DOM_FRAGMENT) { + returnNode = createDocumentFragment.call(body.ownerDocument); + while (body.firstChild) { + // eslint-disable-next-line unicorn/prefer-dom-node-append + returnNode.appendChild(body.firstChild); + } + } else { + returnNode = body; + } + if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) { + /* + AdoptNode() is not used because internal state is not reset + (e.g. the past names map of a HTMLFormElement), this is safe + in theory but we would rather not risk another attack vector. + The state that is cloned by importNode() is explicitly defined + by the specs. + */ + returnNode = importNode.call(originalDocument, returnNode, true); + } + return returnNode; + } + let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; + + /* Serialize doctype if allowed */ + if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) { + serializedHTML = '\n' + serializedHTML; + } + + /* Sanitize final string template-safe */ + if (SAFE_FOR_TEMPLATES) { + arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => { + serializedHTML = stringReplace(serializedHTML, expr, ' '); + }); + } + return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML; + }; + + /** + * Public method to set the configuration once + * setConfig + * + * @param {Object} cfg configuration object + */ + DOMPurify.setConfig = function () { + let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _parseConfig(cfg); + SET_CONFIG = true; + }; + + /** + * Public method to remove the configuration + * clearConfig + * + */ + DOMPurify.clearConfig = function () { + CONFIG = null; + SET_CONFIG = false; + }; + + /** + * Public method to check if an attribute value is valid. + * Uses last set config, if any. Otherwise, uses config defaults. + * isValidAttribute + * + * @param {String} tag Tag name of containing element. + * @param {String} attr Attribute name. + * @param {String} value Attribute value. + * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false. + */ + DOMPurify.isValidAttribute = function (tag, attr, value) { + /* Initialize shared config vars if necessary. */ + if (!CONFIG) { + _parseConfig({}); + } + const lcTag = transformCaseFunc(tag); + const lcName = transformCaseFunc(attr); + return _isValidAttribute(lcTag, lcName, value); + }; + + /** + * AddHook + * Public method to add DOMPurify hooks + * + * @param {String} entryPoint entry point for the hook to add + * @param {Function} hookFunction function to execute + */ + DOMPurify.addHook = function (entryPoint, hookFunction) { + if (typeof hookFunction !== 'function') { + return; + } + hooks[entryPoint] = hooks[entryPoint] || []; + arrayPush(hooks[entryPoint], hookFunction); + }; + + /** + * RemoveHook + * Public method to remove a DOMPurify hook at a given entryPoint + * (pops it from the stack of hooks if more are present) + * + * @param {String} entryPoint entry point for the hook to remove + * @return {Function} removed(popped) hook + */ + DOMPurify.removeHook = function (entryPoint) { + if (hooks[entryPoint]) { + return arrayPop(hooks[entryPoint]); + } + }; + + /** + * RemoveHooks + * Public method to remove all DOMPurify hooks at a given entryPoint + * + * @param {String} entryPoint entry point for the hooks to remove + */ + DOMPurify.removeHooks = function (entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint] = []; + } + }; + + /** + * RemoveAllHooks + * Public method to remove all DOMPurify hooks + */ + DOMPurify.removeAllHooks = function () { + hooks = {}; + }; + return DOMPurify; + } + var purify = createDOMPurify(); + + return purify; + + })); + //# sourceMappingURL=purify.js.map + \ No newline at end of file diff --git a/public/scripts/purify.js.map b/public/scripts/purify.js.map new file mode 100644 index 00000000..da2a374f --- /dev/null +++ b/public/scripts/purify.js.map @@ -0,0 +1 @@ +{"version":3,"file":"purify.js","sources":["../src/utils.js","../src/tags.js","../src/attrs.js","../src/regexp.js","../src/purify.js"],"sourcesContent":["const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n} = Object;\n\nlet { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports\nlet { apply, construct } = typeof Reflect !== 'undefined' && Reflect;\n\nif (!freeze) {\n freeze = function (x) {\n return x;\n };\n}\n\nif (!seal) {\n seal = function (x) {\n return x;\n };\n}\n\nif (!apply) {\n apply = function (fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n}\n\nif (!construct) {\n construct = function (Func, args) {\n return new Func(...args);\n };\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayIndexOf = unapply(Array.prototype.indexOf);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst arraySlice = unapply(Array.prototype.slice);\n\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\n\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n\nconst regExpTest = unapply(RegExp.prototype.test);\n\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply(func) {\n return (thisArg, ...args) => apply(func, thisArg, args);\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct(func) {\n return (...args) => construct(func, args);\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\nfunction addToSet(set, array, transformCaseFunc = stringToLowerCase) {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element] = true;\n }\n\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\nfunction cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\nfunction clone(object) {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (\n value &&\n typeof value === 'object' &&\n value.constructor === Object\n ) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n\n return newObject;\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue() {\n return null;\n }\n\n return fallbackValue;\n}\n\nexport {\n // Array\n arrayForEach,\n arrayIndexOf,\n arrayPop,\n arrayPush,\n arraySlice,\n // Object\n entries,\n freeze,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n isFrozen,\n setPrototypeOf,\n seal,\n clone,\n create,\n objectHasOwnProperty,\n // RegExp\n regExpTest,\n // String\n stringIndexOf,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringTrim,\n // Errors\n typeErrorCreate,\n // Other\n lookupGetter,\n addToSet,\n // Reflect\n unapply,\n unconstruct,\n};\n","import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'a',\n 'abbr',\n 'acronym',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blink',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'content',\n 'data',\n 'datalist',\n 'dd',\n 'decorator',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'element',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'font',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hgroup',\n 'hr',\n 'html',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'marquee',\n 'menu',\n 'menuitem',\n 'meter',\n 'nav',\n 'nobr',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'shadow',\n 'small',\n 'source',\n 'spacer',\n 'span',\n 'strike',\n 'strong',\n 'style',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'tt',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n]);\n\n// SVG\nexport const svg = freeze([\n 'svg',\n 'a',\n 'altglyph',\n 'altglyphdef',\n 'altglyphitem',\n 'animatecolor',\n 'animatemotion',\n 'animatetransform',\n 'circle',\n 'clippath',\n 'defs',\n 'desc',\n 'ellipse',\n 'filter',\n 'font',\n 'g',\n 'glyph',\n 'glyphref',\n 'hkern',\n 'image',\n 'line',\n 'lineargradient',\n 'marker',\n 'mask',\n 'metadata',\n 'mpath',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialgradient',\n 'rect',\n 'stop',\n 'style',\n 'switch',\n 'symbol',\n 'text',\n 'textpath',\n 'title',\n 'tref',\n 'tspan',\n 'view',\n 'vkern',\n]);\n\nexport const svgFilters = freeze([\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n]);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nexport const svgDisallowed = freeze([\n 'animate',\n 'color-profile',\n 'cursor',\n 'discard',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignobject',\n 'hatch',\n 'hatchpath',\n 'mesh',\n 'meshgradient',\n 'meshpatch',\n 'meshrow',\n 'missing-glyph',\n 'script',\n 'set',\n 'solidcolor',\n 'unknown',\n 'use',\n]);\n\nexport const mathMl = freeze([\n 'math',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mglyph',\n 'mi',\n 'mlabeledtr',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'ms',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'mprescripts',\n]);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nexport const mathMlDisallowed = freeze([\n 'maction',\n 'maligngroup',\n 'malignmark',\n 'mlongdiv',\n 'mscarries',\n 'mscarry',\n 'msgroup',\n 'mstack',\n 'msline',\n 'msrow',\n 'semantics',\n 'annotation',\n 'annotation-xml',\n 'mprescripts',\n 'none',\n]);\n\nexport const text = freeze(['#text']);\n","import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'accept',\n 'action',\n 'align',\n 'alt',\n 'autocapitalize',\n 'autocomplete',\n 'autopictureinpicture',\n 'autoplay',\n 'background',\n 'bgcolor',\n 'border',\n 'capture',\n 'cellpadding',\n 'cellspacing',\n 'checked',\n 'cite',\n 'class',\n 'clear',\n 'color',\n 'cols',\n 'colspan',\n 'controls',\n 'controlslist',\n 'coords',\n 'crossorigin',\n 'datetime',\n 'decoding',\n 'default',\n 'dir',\n 'disabled',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'download',\n 'draggable',\n 'enctype',\n 'enterkeyhint',\n 'face',\n 'for',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hreflang',\n 'id',\n 'inputmode',\n 'integrity',\n 'ismap',\n 'kind',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxlength',\n 'media',\n 'method',\n 'min',\n 'minlength',\n 'multiple',\n 'muted',\n 'name',\n 'nonce',\n 'noshade',\n 'novalidate',\n 'nowrap',\n 'open',\n 'optimum',\n 'pattern',\n 'placeholder',\n 'playsinline',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'poster',\n 'preload',\n 'pubdate',\n 'radiogroup',\n 'readonly',\n 'rel',\n 'required',\n 'rev',\n 'reversed',\n 'role',\n 'rows',\n 'rowspan',\n 'spellcheck',\n 'scope',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'span',\n 'srclang',\n 'start',\n 'src',\n 'srcset',\n 'step',\n 'style',\n 'summary',\n 'tabindex',\n 'title',\n 'translate',\n 'type',\n 'usemap',\n 'valign',\n 'value',\n 'width',\n 'wrap',\n 'xmlns',\n 'slot',\n]);\n\nexport const svg = freeze([\n 'accent-height',\n 'accumulate',\n 'additive',\n 'alignment-baseline',\n 'ascent',\n 'attributename',\n 'attributetype',\n 'azimuth',\n 'basefrequency',\n 'baseline-shift',\n 'begin',\n 'bias',\n 'by',\n 'class',\n 'clip',\n 'clippathunits',\n 'clip-path',\n 'clip-rule',\n 'color',\n 'color-interpolation',\n 'color-interpolation-filters',\n 'color-profile',\n 'color-rendering',\n 'cx',\n 'cy',\n 'd',\n 'dx',\n 'dy',\n 'diffuseconstant',\n 'direction',\n 'display',\n 'divisor',\n 'dur',\n 'edgemode',\n 'elevation',\n 'end',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'filter',\n 'filterunits',\n 'flood-color',\n 'flood-opacity',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-weight',\n 'fx',\n 'fy',\n 'g1',\n 'g2',\n 'glyph-name',\n 'glyphref',\n 'gradientunits',\n 'gradienttransform',\n 'height',\n 'href',\n 'id',\n 'image-rendering',\n 'in',\n 'in2',\n 'k',\n 'k1',\n 'k2',\n 'k3',\n 'k4',\n 'kerning',\n 'keypoints',\n 'keysplines',\n 'keytimes',\n 'lang',\n 'lengthadjust',\n 'letter-spacing',\n 'kernelmatrix',\n 'kernelunitlength',\n 'lighting-color',\n 'local',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'markerheight',\n 'markerunits',\n 'markerwidth',\n 'maskcontentunits',\n 'maskunits',\n 'max',\n 'mask',\n 'media',\n 'method',\n 'mode',\n 'min',\n 'name',\n 'numoctaves',\n 'offset',\n 'operator',\n 'opacity',\n 'order',\n 'orient',\n 'orientation',\n 'origin',\n 'overflow',\n 'paint-order',\n 'path',\n 'pathlength',\n 'patterncontentunits',\n 'patterntransform',\n 'patternunits',\n 'points',\n 'preservealpha',\n 'preserveaspectratio',\n 'primitiveunits',\n 'r',\n 'rx',\n 'ry',\n 'radius',\n 'refx',\n 'refy',\n 'repeatcount',\n 'repeatdur',\n 'restart',\n 'result',\n 'rotate',\n 'scale',\n 'seed',\n 'shape-rendering',\n 'specularconstant',\n 'specularexponent',\n 'spreadmethod',\n 'startoffset',\n 'stddeviation',\n 'stitchtiles',\n 'stop-color',\n 'stop-opacity',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-miterlimit',\n 'stroke-opacity',\n 'stroke',\n 'stroke-width',\n 'style',\n 'surfacescale',\n 'systemlanguage',\n 'tabindex',\n 'targetx',\n 'targety',\n 'transform',\n 'transform-origin',\n 'text-anchor',\n 'text-decoration',\n 'text-rendering',\n 'textlength',\n 'type',\n 'u1',\n 'u2',\n 'unicode',\n 'values',\n 'viewbox',\n 'visibility',\n 'version',\n 'vert-adv-y',\n 'vert-origin-x',\n 'vert-origin-y',\n 'width',\n 'word-spacing',\n 'wrap',\n 'writing-mode',\n 'xchannelselector',\n 'ychannelselector',\n 'x',\n 'x1',\n 'x2',\n 'xmlns',\n 'y',\n 'y1',\n 'y2',\n 'z',\n 'zoomandpan',\n]);\n\nexport const mathMl = freeze([\n 'accent',\n 'accentunder',\n 'align',\n 'bevelled',\n 'close',\n 'columnsalign',\n 'columnlines',\n 'columnspan',\n 'denomalign',\n 'depth',\n 'dir',\n 'display',\n 'displaystyle',\n 'encoding',\n 'fence',\n 'frame',\n 'height',\n 'href',\n 'id',\n 'largeop',\n 'length',\n 'linethickness',\n 'lspace',\n 'lquote',\n 'mathbackground',\n 'mathcolor',\n 'mathsize',\n 'mathvariant',\n 'maxsize',\n 'minsize',\n 'movablelimits',\n 'notation',\n 'numalign',\n 'open',\n 'rowalign',\n 'rowlines',\n 'rowspacing',\n 'rowspan',\n 'rspace',\n 'rquote',\n 'scriptlevel',\n 'scriptminsize',\n 'scriptsizemultiplier',\n 'selection',\n 'separator',\n 'separators',\n 'stretchy',\n 'subscriptshift',\n 'supscriptshift',\n 'symmetric',\n 'voffset',\n 'width',\n 'xmlns',\n]);\n\nexport const xml = freeze([\n 'xlink:href',\n 'xml:id',\n 'xlink:title',\n 'xml:space',\n 'xmlns:xlink',\n]);\n","import { seal } from './utils.js';\n\n// eslint-disable-next-line unicorn/better-regex\nexport const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\nexport const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\nexport const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\nexport const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\nexport const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nexport const IS_ALLOWED_URI = seal(\n /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nexport const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nexport const ATTR_WHITESPACE = seal(\n /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nexport const DOCTYPE_NAME = seal(/^html$/i);\nexport const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n","import * as TAGS from './tags.js';\nimport * as ATTRS from './attrs.js';\nimport * as EXPRESSIONS from './regexp.js';\nimport {\n addToSet,\n clone,\n entries,\n freeze,\n arrayForEach,\n arrayPop,\n arrayPush,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringIndexOf,\n stringTrim,\n regExpTest,\n typeErrorCreate,\n lookupGetter,\n create,\n objectHasOwnProperty,\n} from './utils.js';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5, // Deprecated\n entityNode: 6, // Deprecated\n progressingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12, // Deprecated\n};\n\nconst getGlobal = function () {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function (trustedTypes, purifyHostElement) {\n if (\n typeof trustedTypes !== 'object' ||\n typeof trustedTypes.createPolicy !== 'function'\n ) {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n },\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn(\n 'TrustedTypes policy ' + policyName + ' could not be created.'\n );\n return null;\n }\n};\n\nfunction createDOMPurify(window = getGlobal()) {\n const DOMPurify = (root) => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = VERSION;\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n\n if (\n !window ||\n !window.document ||\n window.document.nodeType !== NODE_TYPE.document\n ) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n let { document } = window;\n\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes,\n } = window;\n\n const ElementPrototype = Element.prototype;\n\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const remove = lookupGetter(ElementPrototype, 'remove');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName,\n } = document;\n const { importNode } = originalDocument;\n\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported =\n typeof entries === 'function' &&\n typeof getParentNode === 'function' &&\n implementation &&\n implementation.createHTMLDocument !== undefined;\n\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT,\n } = EXPRESSIONS;\n\n let { IS_ALLOWED_URI } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [\n ...TAGS.html,\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.mathMl,\n ...TAGS.text,\n ]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [\n ...ATTRS.html,\n ...ATTRS.svg,\n ...ATTRS.mathMl,\n ...ATTRS.xml,\n ]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false,\n },\n })\n );\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with ... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, [\n 'annotation-xml',\n 'audio',\n 'colgroup',\n 'desc',\n 'foreignobject',\n 'head',\n 'iframe',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mtext',\n 'noembed',\n 'noframes',\n 'noscript',\n 'plaintext',\n 'script',\n 'style',\n 'svg',\n 'template',\n 'thead',\n 'title',\n 'video',\n 'xmp',\n ]);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, [\n 'audio',\n 'video',\n 'img',\n 'source',\n 'image',\n 'track',\n ]);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [\n 'alt',\n 'class',\n 'for',\n 'id',\n 'label',\n 'name',\n 'pattern',\n 'placeholder',\n 'role',\n 'summary',\n 'title',\n 'value',\n 'style',\n 'xmlns',\n ]);\n\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet(\n {},\n [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE],\n stringToString\n );\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n\n const isRegexOrFunction = function (testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function (cfg = {}) {\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1\n ? DEFAULT_PARSER_MEDIA_TYPE\n : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc =\n PARSER_MEDIA_TYPE === 'application/xhtml+xml'\n ? stringToString\n : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS')\n ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)\n : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR')\n ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)\n : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES')\n ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString)\n : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR')\n ? addToSet(\n clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS')\n ? addToSet(\n clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS')\n ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc)\n : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS')\n ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc)\n : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR')\n ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc)\n : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES')\n ? cfg.USE_PROFILES\n : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI = cfg.ALLOWED_URI_REGEXP || EXPRESSIONS.IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements ===\n 'boolean'\n ) {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =\n cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, TAGS.text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, TAGS.html);\n addToSet(ALLOWED_ATTR, ATTRS.html);\n }\n\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, TAGS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, TAGS.svgFilters);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, TAGS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.'\n );\n }\n\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.'\n );\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(\n trustedTypes,\n currentScript\n );\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n\n CONFIG = cfg;\n };\n\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n ]);\n\n const HTML_INTEGRATION_POINTS = addToSet({}, [\n 'foreignobject',\n 'annotation-xml',\n ]);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [\n 'title',\n 'style',\n 'font',\n 'a',\n 'script',\n ]);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.svgDisallowed,\n ]);\n const ALL_MATHML_TAGS = addToSet({}, [\n ...TAGS.mathMl,\n ...TAGS.mathMlDisallowed,\n ]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function (element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template',\n };\n }\n\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return (\n tagName === 'svg' &&\n (parentTagName === 'annotation-xml' ||\n MATHML_TEXT_INTEGRATION_POINTS[parentTagName])\n );\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (\n parent.namespaceURI === SVG_NAMESPACE &&\n !HTML_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n if (\n parent.namespaceURI === MATHML_NAMESPACE &&\n !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return (\n !ALL_MATHML_TAGS[tagName] &&\n (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName])\n );\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n ALLOWED_NAMESPACES[element.namespaceURI]\n ) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function (node) {\n arrayPush(DOMPurify.removed, { element: node });\n\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n getParentNode(node).removeChild(node);\n } catch (_) {\n remove(node);\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function (name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node,\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node,\n });\n }\n\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function (dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n\n if (FORCE_BODY) {\n dirty = '' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n NAMESPACE === HTML_NAMESPACE\n ) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty =\n '' +\n dirty +\n '';\n }\n\n const dirtyPayload = trustedTypesPolicy\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT\n ? emptyHTML\n : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n\n const body = doc.body || doc.documentElement;\n\n if (dirty && leadingWhitespace) {\n body.insertBefore(\n document.createTextNode(leadingWhitespace),\n body.childNodes[0] || null\n );\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(\n doc,\n WHOLE_DOCUMENT ? 'html' : 'body'\n )[0];\n }\n\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function (root) {\n return createNodeIterator.call(\n root.ownerDocument || root,\n root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT |\n NodeFilter.SHOW_COMMENT |\n NodeFilter.SHOW_TEXT |\n NodeFilter.SHOW_PROCESSING_INSTRUCTION |\n NodeFilter.SHOW_CDATA_SECTION,\n null\n );\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function (elm) {\n return (\n elm instanceof HTMLFormElement &&\n (typeof elm.nodeName !== 'string' ||\n typeof elm.textContent !== 'string' ||\n typeof elm.removeChild !== 'function' ||\n !(elm.attributes instanceof NamedNodeMap) ||\n typeof elm.removeAttribute !== 'function' ||\n typeof elm.setAttribute !== 'function' ||\n typeof elm.namespaceURI !== 'string' ||\n typeof elm.insertBefore !== 'function' ||\n typeof elm.hasChildNodes !== 'function')\n );\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function (object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function (entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n\n arrayForEach(hooks[entryPoint], (hook) => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function (currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS,\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (\n currentNode.hasChildNodes() &&\n !_isNode(currentNode.firstElementChild) &&\n regExpTest(/<[/\\w]/g, currentNode.innerHTML) &&\n regExpTest(/<[/\\w]/g, currentNode.textContent)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any occurrence of processing instructions */\n if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (\n SAFE_FOR_XML &&\n currentNode.nodeType === NODE_TYPE.comment &&\n regExpTest(/<[/\\w]/g, currentNode.data)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)\n ) {\n return false;\n }\n\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)\n ) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n\n for (let i = childCount - 1; i >= 0; --i) {\n const childClone = cloneNode(childNodes[i], true);\n childClone.__removalCount = (currentNode.__removalCount || 0) + 1;\n parentNode.insertBefore(childClone, getNextSibling(currentNode));\n }\n }\n }\n\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if (\n (tagName === 'noscript' ||\n tagName === 'noembed' ||\n tagName === 'noframes') &&\n regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {\n /* Get the element's text content */\n content = currentNode.textContent;\n\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n content = stringReplace(content, expr, ' ');\n });\n\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function (lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (\n SANITIZE_DOM &&\n (lcName === 'id' || lcName === 'name') &&\n (value in document || value in formElement)\n ) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n if (\n ALLOW_DATA_ATTR &&\n !FORBID_ATTR[lcName] &&\n regExpTest(DATA_ATTR, lcName)\n ) {\n // This attribute is safe\n } else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) {\n // This attribute is safe\n /* Otherwise, check the name is permitted */\n } else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n (_isBasicCustomElement(lcTag) &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag))) &&\n ((CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName)) ||\n (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)))) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n (lcName === 'is' &&\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))))\n ) {\n // If user has supplied a regexp or function in CUSTOM_ELEMENT_HANDLING.tagNameCheck, we need to also allow derived custom elements using the same tagName test.\n // Additionally, we need to allow attributes passing the CUSTOM_ELEMENT_HANDLING.attributeNameCheck user has configured, as custom elements can define these at their own discretion.\n } else {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } else if (URI_SAFE_ATTRIBUTES[lcName]) {\n // This attribute is safe\n /* Check no script, data or unknown possibly unsafe URI\n unless we know URI values are safe for that attribute */\n } else if (\n regExpTest(IS_ALLOWED_URI, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Keep image data URIs alive if src/xlink:href is allowed */\n /* Further prevent gadget XSS for dynamically built script tags */\n } else if (\n (lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') &&\n lcTag !== 'script' &&\n stringIndexOf(value, 'data:') === 0 &&\n DATA_URI_TAGS[lcTag]\n ) {\n // This attribute is safe\n /* Allow unknown protocols: This provides support for links that\n are handled by protocol handlers which may be unknown ahead of\n time, e.g. fb:, spotify: */\n } else if (\n ALLOW_UNKNOWN_PROTOCOLS &&\n !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Check for binary attributes */\n } else if (value) {\n return false;\n } else {\n // Binary attributes are safe at this point\n /* Anything else, presume unsafe, do not add it back */\n }\n\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function (tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function (currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n\n const { attributes } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR,\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const { name, namespaceURI, value: attrValue } = attr;\n const lcName = transformCaseFunc(name);\n\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n\n /* Work around a security issue with comments inside attributes */\n if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\\/(style|title)/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Handle attributes that require Trusted Types */\n if (\n trustedTypesPolicy &&\n typeof trustedTypes === 'object' &&\n typeof trustedTypes.getAttributeType === 'function'\n ) {\n if (namespaceURI) {\n /* Namespaces are not yet supported, see https://bugs.chromium.org/p/chromium/issues/detail?id=1305293 */\n } else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML': {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n\n case 'TrustedScriptURL': {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n\n default: {\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n } else {\n arrayPop(DOMPurify.removed);\n }\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function (fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n\n while ((shadowNode = shadowIterator.nextNode())) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty, cfg = {}) {\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate(\n 'root node is forbidden and cannot be sanitized in-place'\n );\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (\n importedNode.nodeType === NODE_TYPE.element &&\n importedNode.nodeName === 'BODY'\n ) {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (\n !RETURN_DOM &&\n !SAFE_FOR_TEMPLATES &&\n !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1\n ) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while ((currentNode = nodeIterator.nextNode())) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n\n return returnNode;\n }\n\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (\n WHOLE_DOCUMENT &&\n ALLOWED_TAGS['!doctype'] &&\n body.ownerDocument &&\n body.ownerDocument.doctype &&\n body.ownerDocument.doctype.name &&\n regExpTest(EXPRESSIONS.DOCTYPE_NAME, body.ownerDocument.doctype.name)\n ) {\n serializedHTML =\n '\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(serializedHTML)\n : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function (cfg = {}) {\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n\n return DOMPurify;\n}\n\nexport default createDOMPurify();\n"],"names":["entries","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","Object","freeze","seal","create","apply","construct","Reflect","x","fun","thisValue","args","Func","arrayForEach","unapply","Array","prototype","forEach","arrayPop","pop","arrayPush","push","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","objectHasOwnProperty","hasOwnProperty","regExpTest","RegExp","test","typeErrorCreate","unconstruct","TypeError","func","thisArg","_len","arguments","length","_key","_len2","_key2","addToSet","set","array","transformCaseFunc","undefined","l","element","lcElement","cleanArray","index","isPropertyExist","clone","object","newObject","property","value","isArray","constructor","lookupGetter","prop","desc","get","fallbackValue","html","svg","svgFilters","svgDisallowed","mathMl","mathMlDisallowed","text","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","NODE_TYPE","attribute","cdataSection","entityReference","entityNode","progressingInstruction","comment","document","documentType","documentFragment","notation","getGlobal","window","_createTrustedTypesPolicy","trustedTypes","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","createHTML","createScriptURL","scriptUrl","_","console","warn","createDOMPurify","DOMPurify","root","version","VERSION","removed","nodeType","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","Element","NodeFilter","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","createHTMLDocument","EXPRESSIONS","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","ATTRS","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","SANITIZE_NAMED_PROPS_PREFIX","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","DEFAULT_PARSER_MEDIA_TYPE","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","ALLOWED_URI_REGEXP","ADD_TAGS","ADD_ATTR","table","tbody","TRUSTED_TYPES_POLICY","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","ALL_SVG_TAGS","ALL_MATHML_TAGS","_checkValidNamespace","parent","tagName","namespaceURI","parentTagName","Boolean","_forceRemove","node","removeChild","_removeAttribute","name","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_isClobbered","elm","nodeName","textContent","attributes","hasChildNodes","_isNode","_executeHook","entryPoint","currentNode","data","hook","_sanitizeElements","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","childCount","i","childClone","__removalCount","expr","_isValidAttribute","lcTag","lcName","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","attr","forceKeepAttr","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","nextNode","sanitize","importedNode","returnNode","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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"} \ No newline at end of file diff --git a/public/scripts/purify.min.js.map b/public/scripts/purify.min.js.map new file mode 100644 index 00000000..af5eff08 --- /dev/null +++ b/public/scripts/purify.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"purify.min.js","sources":["../src/utils.js","../src/tags.js","../src/attrs.js","../src/regexp.js","../src/purify.js"],"sourcesContent":["const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n} = Object;\n\nlet { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports\nlet { apply, construct } = typeof Reflect !== 'undefined' && Reflect;\n\nif (!freeze) {\n freeze = function (x) {\n return x;\n };\n}\n\nif (!seal) {\n seal = function (x) {\n return x;\n };\n}\n\nif (!apply) {\n apply = function (fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n}\n\nif (!construct) {\n construct = function (Func, args) {\n return new Func(...args);\n };\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayIndexOf = unapply(Array.prototype.indexOf);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst arraySlice = unapply(Array.prototype.slice);\n\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\n\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n\nconst regExpTest = unapply(RegExp.prototype.test);\n\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply(func) {\n return (thisArg, ...args) => apply(func, thisArg, args);\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct(func) {\n return (...args) => construct(func, args);\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\nfunction addToSet(set, array, transformCaseFunc = stringToLowerCase) {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element] = true;\n }\n\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\nfunction cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\nfunction clone(object) {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (\n value &&\n typeof value === 'object' &&\n value.constructor === Object\n ) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n\n return newObject;\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue() {\n return null;\n }\n\n return fallbackValue;\n}\n\nexport {\n // Array\n arrayForEach,\n arrayIndexOf,\n arrayPop,\n arrayPush,\n arraySlice,\n // Object\n entries,\n freeze,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n isFrozen,\n setPrototypeOf,\n seal,\n clone,\n create,\n objectHasOwnProperty,\n // RegExp\n regExpTest,\n // String\n stringIndexOf,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringTrim,\n // Errors\n typeErrorCreate,\n // Other\n lookupGetter,\n addToSet,\n // Reflect\n unapply,\n unconstruct,\n};\n","import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'a',\n 'abbr',\n 'acronym',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blink',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'content',\n 'data',\n 'datalist',\n 'dd',\n 'decorator',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'element',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'font',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hgroup',\n 'hr',\n 'html',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'marquee',\n 'menu',\n 'menuitem',\n 'meter',\n 'nav',\n 'nobr',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'shadow',\n 'small',\n 'source',\n 'spacer',\n 'span',\n 'strike',\n 'strong',\n 'style',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'tt',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n]);\n\n// SVG\nexport const svg = freeze([\n 'svg',\n 'a',\n 'altglyph',\n 'altglyphdef',\n 'altglyphitem',\n 'animatecolor',\n 'animatemotion',\n 'animatetransform',\n 'circle',\n 'clippath',\n 'defs',\n 'desc',\n 'ellipse',\n 'filter',\n 'font',\n 'g',\n 'glyph',\n 'glyphref',\n 'hkern',\n 'image',\n 'line',\n 'lineargradient',\n 'marker',\n 'mask',\n 'metadata',\n 'mpath',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialgradient',\n 'rect',\n 'stop',\n 'style',\n 'switch',\n 'symbol',\n 'text',\n 'textpath',\n 'title',\n 'tref',\n 'tspan',\n 'view',\n 'vkern',\n]);\n\nexport const svgFilters = freeze([\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n]);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nexport const svgDisallowed = freeze([\n 'animate',\n 'color-profile',\n 'cursor',\n 'discard',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignobject',\n 'hatch',\n 'hatchpath',\n 'mesh',\n 'meshgradient',\n 'meshpatch',\n 'meshrow',\n 'missing-glyph',\n 'script',\n 'set',\n 'solidcolor',\n 'unknown',\n 'use',\n]);\n\nexport const mathMl = freeze([\n 'math',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mglyph',\n 'mi',\n 'mlabeledtr',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'ms',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'mprescripts',\n]);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nexport const mathMlDisallowed = freeze([\n 'maction',\n 'maligngroup',\n 'malignmark',\n 'mlongdiv',\n 'mscarries',\n 'mscarry',\n 'msgroup',\n 'mstack',\n 'msline',\n 'msrow',\n 'semantics',\n 'annotation',\n 'annotation-xml',\n 'mprescripts',\n 'none',\n]);\n\nexport const text = freeze(['#text']);\n","import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'accept',\n 'action',\n 'align',\n 'alt',\n 'autocapitalize',\n 'autocomplete',\n 'autopictureinpicture',\n 'autoplay',\n 'background',\n 'bgcolor',\n 'border',\n 'capture',\n 'cellpadding',\n 'cellspacing',\n 'checked',\n 'cite',\n 'class',\n 'clear',\n 'color',\n 'cols',\n 'colspan',\n 'controls',\n 'controlslist',\n 'coords',\n 'crossorigin',\n 'datetime',\n 'decoding',\n 'default',\n 'dir',\n 'disabled',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'download',\n 'draggable',\n 'enctype',\n 'enterkeyhint',\n 'face',\n 'for',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hreflang',\n 'id',\n 'inputmode',\n 'integrity',\n 'ismap',\n 'kind',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxlength',\n 'media',\n 'method',\n 'min',\n 'minlength',\n 'multiple',\n 'muted',\n 'name',\n 'nonce',\n 'noshade',\n 'novalidate',\n 'nowrap',\n 'open',\n 'optimum',\n 'pattern',\n 'placeholder',\n 'playsinline',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'poster',\n 'preload',\n 'pubdate',\n 'radiogroup',\n 'readonly',\n 'rel',\n 'required',\n 'rev',\n 'reversed',\n 'role',\n 'rows',\n 'rowspan',\n 'spellcheck',\n 'scope',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'span',\n 'srclang',\n 'start',\n 'src',\n 'srcset',\n 'step',\n 'style',\n 'summary',\n 'tabindex',\n 'title',\n 'translate',\n 'type',\n 'usemap',\n 'valign',\n 'value',\n 'width',\n 'wrap',\n 'xmlns',\n 'slot',\n]);\n\nexport const svg = freeze([\n 'accent-height',\n 'accumulate',\n 'additive',\n 'alignment-baseline',\n 'ascent',\n 'attributename',\n 'attributetype',\n 'azimuth',\n 'basefrequency',\n 'baseline-shift',\n 'begin',\n 'bias',\n 'by',\n 'class',\n 'clip',\n 'clippathunits',\n 'clip-path',\n 'clip-rule',\n 'color',\n 'color-interpolation',\n 'color-interpolation-filters',\n 'color-profile',\n 'color-rendering',\n 'cx',\n 'cy',\n 'd',\n 'dx',\n 'dy',\n 'diffuseconstant',\n 'direction',\n 'display',\n 'divisor',\n 'dur',\n 'edgemode',\n 'elevation',\n 'end',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'filter',\n 'filterunits',\n 'flood-color',\n 'flood-opacity',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-weight',\n 'fx',\n 'fy',\n 'g1',\n 'g2',\n 'glyph-name',\n 'glyphref',\n 'gradientunits',\n 'gradienttransform',\n 'height',\n 'href',\n 'id',\n 'image-rendering',\n 'in',\n 'in2',\n 'k',\n 'k1',\n 'k2',\n 'k3',\n 'k4',\n 'kerning',\n 'keypoints',\n 'keysplines',\n 'keytimes',\n 'lang',\n 'lengthadjust',\n 'letter-spacing',\n 'kernelmatrix',\n 'kernelunitlength',\n 'lighting-color',\n 'local',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'markerheight',\n 'markerunits',\n 'markerwidth',\n 'maskcontentunits',\n 'maskunits',\n 'max',\n 'mask',\n 'media',\n 'method',\n 'mode',\n 'min',\n 'name',\n 'numoctaves',\n 'offset',\n 'operator',\n 'opacity',\n 'order',\n 'orient',\n 'orientation',\n 'origin',\n 'overflow',\n 'paint-order',\n 'path',\n 'pathlength',\n 'patterncontentunits',\n 'patterntransform',\n 'patternunits',\n 'points',\n 'preservealpha',\n 'preserveaspectratio',\n 'primitiveunits',\n 'r',\n 'rx',\n 'ry',\n 'radius',\n 'refx',\n 'refy',\n 'repeatcount',\n 'repeatdur',\n 'restart',\n 'result',\n 'rotate',\n 'scale',\n 'seed',\n 'shape-rendering',\n 'specularconstant',\n 'specularexponent',\n 'spreadmethod',\n 'startoffset',\n 'stddeviation',\n 'stitchtiles',\n 'stop-color',\n 'stop-opacity',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-miterlimit',\n 'stroke-opacity',\n 'stroke',\n 'stroke-width',\n 'style',\n 'surfacescale',\n 'systemlanguage',\n 'tabindex',\n 'targetx',\n 'targety',\n 'transform',\n 'transform-origin',\n 'text-anchor',\n 'text-decoration',\n 'text-rendering',\n 'textlength',\n 'type',\n 'u1',\n 'u2',\n 'unicode',\n 'values',\n 'viewbox',\n 'visibility',\n 'version',\n 'vert-adv-y',\n 'vert-origin-x',\n 'vert-origin-y',\n 'width',\n 'word-spacing',\n 'wrap',\n 'writing-mode',\n 'xchannelselector',\n 'ychannelselector',\n 'x',\n 'x1',\n 'x2',\n 'xmlns',\n 'y',\n 'y1',\n 'y2',\n 'z',\n 'zoomandpan',\n]);\n\nexport const mathMl = freeze([\n 'accent',\n 'accentunder',\n 'align',\n 'bevelled',\n 'close',\n 'columnsalign',\n 'columnlines',\n 'columnspan',\n 'denomalign',\n 'depth',\n 'dir',\n 'display',\n 'displaystyle',\n 'encoding',\n 'fence',\n 'frame',\n 'height',\n 'href',\n 'id',\n 'largeop',\n 'length',\n 'linethickness',\n 'lspace',\n 'lquote',\n 'mathbackground',\n 'mathcolor',\n 'mathsize',\n 'mathvariant',\n 'maxsize',\n 'minsize',\n 'movablelimits',\n 'notation',\n 'numalign',\n 'open',\n 'rowalign',\n 'rowlines',\n 'rowspacing',\n 'rowspan',\n 'rspace',\n 'rquote',\n 'scriptlevel',\n 'scriptminsize',\n 'scriptsizemultiplier',\n 'selection',\n 'separator',\n 'separators',\n 'stretchy',\n 'subscriptshift',\n 'supscriptshift',\n 'symmetric',\n 'voffset',\n 'width',\n 'xmlns',\n]);\n\nexport const xml = freeze([\n 'xlink:href',\n 'xml:id',\n 'xlink:title',\n 'xml:space',\n 'xmlns:xlink',\n]);\n","import { seal } from './utils.js';\n\n// eslint-disable-next-line unicorn/better-regex\nexport const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\nexport const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\nexport const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\nexport const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\nexport const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nexport const IS_ALLOWED_URI = seal(\n /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nexport const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nexport const ATTR_WHITESPACE = seal(\n /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nexport const DOCTYPE_NAME = seal(/^html$/i);\nexport const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n","import * as TAGS from './tags.js';\nimport * as ATTRS from './attrs.js';\nimport * as EXPRESSIONS from './regexp.js';\nimport {\n addToSet,\n clone,\n entries,\n freeze,\n arrayForEach,\n arrayPop,\n arrayPush,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringIndexOf,\n stringTrim,\n regExpTest,\n typeErrorCreate,\n lookupGetter,\n create,\n objectHasOwnProperty,\n} from './utils.js';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5, // Deprecated\n entityNode: 6, // Deprecated\n progressingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12, // Deprecated\n};\n\nconst getGlobal = function () {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function (trustedTypes, purifyHostElement) {\n if (\n typeof trustedTypes !== 'object' ||\n typeof trustedTypes.createPolicy !== 'function'\n ) {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n },\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn(\n 'TrustedTypes policy ' + policyName + ' could not be created.'\n );\n return null;\n }\n};\n\nfunction createDOMPurify(window = getGlobal()) {\n const DOMPurify = (root) => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = VERSION;\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n\n if (\n !window ||\n !window.document ||\n window.document.nodeType !== NODE_TYPE.document\n ) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n let { document } = window;\n\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes,\n } = window;\n\n const ElementPrototype = Element.prototype;\n\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const remove = lookupGetter(ElementPrototype, 'remove');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName,\n } = document;\n const { importNode } = originalDocument;\n\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported =\n typeof entries === 'function' &&\n typeof getParentNode === 'function' &&\n implementation &&\n implementation.createHTMLDocument !== undefined;\n\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT,\n } = EXPRESSIONS;\n\n let { IS_ALLOWED_URI } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [\n ...TAGS.html,\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.mathMl,\n ...TAGS.text,\n ]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [\n ...ATTRS.html,\n ...ATTRS.svg,\n ...ATTRS.mathMl,\n ...ATTRS.xml,\n ]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false,\n },\n })\n );\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with ... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, [\n 'annotation-xml',\n 'audio',\n 'colgroup',\n 'desc',\n 'foreignobject',\n 'head',\n 'iframe',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mtext',\n 'noembed',\n 'noframes',\n 'noscript',\n 'plaintext',\n 'script',\n 'style',\n 'svg',\n 'template',\n 'thead',\n 'title',\n 'video',\n 'xmp',\n ]);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, [\n 'audio',\n 'video',\n 'img',\n 'source',\n 'image',\n 'track',\n ]);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [\n 'alt',\n 'class',\n 'for',\n 'id',\n 'label',\n 'name',\n 'pattern',\n 'placeholder',\n 'role',\n 'summary',\n 'title',\n 'value',\n 'style',\n 'xmlns',\n ]);\n\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet(\n {},\n [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE],\n stringToString\n );\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n\n const isRegexOrFunction = function (testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function (cfg = {}) {\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1\n ? DEFAULT_PARSER_MEDIA_TYPE\n : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc =\n PARSER_MEDIA_TYPE === 'application/xhtml+xml'\n ? stringToString\n : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS')\n ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)\n : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR')\n ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)\n : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES')\n ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString)\n : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR')\n ? addToSet(\n clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS')\n ? addToSet(\n clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS')\n ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc)\n : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS')\n ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc)\n : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR')\n ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc)\n : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES')\n ? cfg.USE_PROFILES\n : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI = cfg.ALLOWED_URI_REGEXP || EXPRESSIONS.IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements ===\n 'boolean'\n ) {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =\n cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, TAGS.text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, TAGS.html);\n addToSet(ALLOWED_ATTR, ATTRS.html);\n }\n\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, TAGS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, TAGS.svgFilters);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, TAGS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.'\n );\n }\n\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.'\n );\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(\n trustedTypes,\n currentScript\n );\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n\n CONFIG = cfg;\n };\n\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n ]);\n\n const HTML_INTEGRATION_POINTS = addToSet({}, [\n 'foreignobject',\n 'annotation-xml',\n ]);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [\n 'title',\n 'style',\n 'font',\n 'a',\n 'script',\n ]);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.svgDisallowed,\n ]);\n const ALL_MATHML_TAGS = addToSet({}, [\n ...TAGS.mathMl,\n ...TAGS.mathMlDisallowed,\n ]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function (element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template',\n };\n }\n\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return (\n tagName === 'svg' &&\n (parentTagName === 'annotation-xml' ||\n MATHML_TEXT_INTEGRATION_POINTS[parentTagName])\n );\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (\n parent.namespaceURI === SVG_NAMESPACE &&\n !HTML_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n if (\n parent.namespaceURI === MATHML_NAMESPACE &&\n !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return (\n !ALL_MATHML_TAGS[tagName] &&\n (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName])\n );\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n ALLOWED_NAMESPACES[element.namespaceURI]\n ) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function (node) {\n arrayPush(DOMPurify.removed, { element: node });\n\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n getParentNode(node).removeChild(node);\n } catch (_) {\n remove(node);\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function (name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node,\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node,\n });\n }\n\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function (dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n\n if (FORCE_BODY) {\n dirty = '' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n NAMESPACE === HTML_NAMESPACE\n ) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty =\n '' +\n dirty +\n '';\n }\n\n const dirtyPayload = trustedTypesPolicy\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT\n ? emptyHTML\n : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n\n const body = doc.body || doc.documentElement;\n\n if (dirty && leadingWhitespace) {\n body.insertBefore(\n document.createTextNode(leadingWhitespace),\n body.childNodes[0] || null\n );\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(\n doc,\n WHOLE_DOCUMENT ? 'html' : 'body'\n )[0];\n }\n\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function (root) {\n return createNodeIterator.call(\n root.ownerDocument || root,\n root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT |\n NodeFilter.SHOW_COMMENT |\n NodeFilter.SHOW_TEXT |\n NodeFilter.SHOW_PROCESSING_INSTRUCTION |\n NodeFilter.SHOW_CDATA_SECTION,\n null\n );\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function (elm) {\n return (\n elm instanceof HTMLFormElement &&\n (typeof elm.nodeName !== 'string' ||\n typeof elm.textContent !== 'string' ||\n typeof elm.removeChild !== 'function' ||\n !(elm.attributes instanceof NamedNodeMap) ||\n typeof elm.removeAttribute !== 'function' ||\n typeof elm.setAttribute !== 'function' ||\n typeof elm.namespaceURI !== 'string' ||\n typeof elm.insertBefore !== 'function' ||\n typeof elm.hasChildNodes !== 'function')\n );\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function (object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function (entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n\n arrayForEach(hooks[entryPoint], (hook) => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function (currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS,\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (\n currentNode.hasChildNodes() &&\n !_isNode(currentNode.firstElementChild) &&\n regExpTest(/<[/\\w]/g, currentNode.innerHTML) &&\n regExpTest(/<[/\\w]/g, currentNode.textContent)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any occurrence of processing instructions */\n if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (\n SAFE_FOR_XML &&\n currentNode.nodeType === NODE_TYPE.comment &&\n regExpTest(/<[/\\w]/g, currentNode.data)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)\n ) {\n return false;\n }\n\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)\n ) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n\n for (let i = childCount - 1; i >= 0; --i) {\n const childClone = cloneNode(childNodes[i], true);\n childClone.__removalCount = (currentNode.__removalCount || 0) + 1;\n parentNode.insertBefore(childClone, getNextSibling(currentNode));\n }\n }\n }\n\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if (\n (tagName === 'noscript' ||\n tagName === 'noembed' ||\n tagName === 'noframes') &&\n regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {\n /* Get the element's text content */\n content = currentNode.textContent;\n\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n content = stringReplace(content, expr, ' ');\n });\n\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function (lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (\n SANITIZE_DOM &&\n (lcName === 'id' || lcName === 'name') &&\n (value in document || value in formElement)\n ) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n if (\n ALLOW_DATA_ATTR &&\n !FORBID_ATTR[lcName] &&\n regExpTest(DATA_ATTR, lcName)\n ) {\n // This attribute is safe\n } else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) {\n // This attribute is safe\n /* Otherwise, check the name is permitted */\n } else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n (_isBasicCustomElement(lcTag) &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag))) &&\n ((CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName)) ||\n (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)))) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n (lcName === 'is' &&\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))))\n ) {\n // If user has supplied a regexp or function in CUSTOM_ELEMENT_HANDLING.tagNameCheck, we need to also allow derived custom elements using the same tagName test.\n // Additionally, we need to allow attributes passing the CUSTOM_ELEMENT_HANDLING.attributeNameCheck user has configured, as custom elements can define these at their own discretion.\n } else {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } else if (URI_SAFE_ATTRIBUTES[lcName]) {\n // This attribute is safe\n /* Check no script, data or unknown possibly unsafe URI\n unless we know URI values are safe for that attribute */\n } else if (\n regExpTest(IS_ALLOWED_URI, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Keep image data URIs alive if src/xlink:href is allowed */\n /* Further prevent gadget XSS for dynamically built script tags */\n } else if (\n (lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') &&\n lcTag !== 'script' &&\n stringIndexOf(value, 'data:') === 0 &&\n DATA_URI_TAGS[lcTag]\n ) {\n // This attribute is safe\n /* Allow unknown protocols: This provides support for links that\n are handled by protocol handlers which may be unknown ahead of\n time, e.g. fb:, spotify: */\n } else if (\n ALLOW_UNKNOWN_PROTOCOLS &&\n !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Check for binary attributes */\n } else if (value) {\n return false;\n } else {\n // Binary attributes are safe at this point\n /* Anything else, presume unsafe, do not add it back */\n }\n\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function (tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function (currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n\n const { attributes } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR,\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const { name, namespaceURI, value: attrValue } = attr;\n const lcName = transformCaseFunc(name);\n\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n\n /* Work around a security issue with comments inside attributes */\n if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\\/(style|title)/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Handle attributes that require Trusted Types */\n if (\n trustedTypesPolicy &&\n typeof trustedTypes === 'object' &&\n typeof trustedTypes.getAttributeType === 'function'\n ) {\n if (namespaceURI) {\n /* Namespaces are not yet supported, see https://bugs.chromium.org/p/chromium/issues/detail?id=1305293 */\n } else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML': {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n\n case 'TrustedScriptURL': {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n\n default: {\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n } else {\n arrayPop(DOMPurify.removed);\n }\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function (fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n\n while ((shadowNode = shadowIterator.nextNode())) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty, cfg = {}) {\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate(\n 'root node is forbidden and cannot be sanitized in-place'\n );\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (\n importedNode.nodeType === NODE_TYPE.element &&\n importedNode.nodeName === 'BODY'\n ) {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (\n !RETURN_DOM &&\n !SAFE_FOR_TEMPLATES &&\n !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1\n ) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while ((currentNode = nodeIterator.nextNode())) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n\n return returnNode;\n }\n\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (\n WHOLE_DOCUMENT &&\n ALLOWED_TAGS['!doctype'] &&\n body.ownerDocument &&\n body.ownerDocument.doctype &&\n body.ownerDocument.doctype.name &&\n regExpTest(EXPRESSIONS.DOCTYPE_NAME, body.ownerDocument.doctype.name)\n ) {\n serializedHTML =\n '\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(serializedHTML)\n : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function (cfg = {}) {\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n\n return DOMPurify;\n}\n\nexport default createDOMPurify();\n"],"names":["entries","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","Object","freeze","seal","create","apply","construct","Reflect","x","fun","thisValue","args","Func","arrayForEach","unapply","Array","prototype","forEach","arrayPop","pop","arrayPush","push","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","objectHasOwnProperty","hasOwnProperty","regExpTest","RegExp","test","typeErrorCreate","func","TypeError","_len2","arguments","length","_key2","thisArg","_len","_key","addToSet","set","array","transformCaseFunc","undefined","l","element","lcElement","cleanArray","index","clone","object","newObject","property","value","isArray","constructor","lookupGetter","prop","desc","get","html","svg","svgFilters","svgDisallowed","mathMl","mathMlDisallowed","text","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","NODE_TYPE","getGlobal","window","purify","createDOMPurify","DOMPurify","root","version","VERSION","removed","document","nodeType","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","Element","NodeFilter","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","createHTMLDocument","EXPRESSIONS","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","ATTRS","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","ALLOWED_URI_REGEXP","ADD_TAGS","ADD_ATTR","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","removeChild","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_isClobbered","elm","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isNode","_executeHook","entryPoint","currentNode","data","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","i","childClone","__removalCount","parent","parentTagName","Boolean","_checkValidNamespace","expr","_isValidAttribute","lcTag","lcName","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","attr","forceKeepAttr","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","nextNode","sanitize","importedNode","returnNode","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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ACA,QACA,SACA,KACA,OACA,MACA,OACA,UACA,OACA,WACA,QACA,MACA,OACA,KACA,WACA,SACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,UACA,SACA,SACA,QACA,SACA,SACA,OACA,SACA,SACA,QACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,WACA,QACA,KACA,QACA,OACA,KACA,QACA,KACA,IACA,KACA,MACA,QACA,QAIWsE,EAAMtE,EAAO,CACxB,MACA,IACA,WACA,cACA,eACA,eACA,gBACA,mBACA,SACA,WACA,OACA,OACA,UACA,SACA,OACA,IACA,QACA,WACA,QACA,QACA,OACA,iBACA,SACA,OACA,WACA,QACA,OACA,UACA,UACA,WACA,iBACA,OACA,OACA,QACA,SACA,SACA,OACA,WACA,QACA,OACA,QACA,OACA,UAGWuE,EAAavE,EAAO,CAC/B,UACA,gBACA,sBACA,cACA,mBACA,oBACA,oBACA,iBACA,eACA,UACA,UACA,UACA,UACA,UACA,iBACA,UACA,UACA,cACA,eACA,WACA,eACA,qBACA,cACA,SACA,iBAOWwE,EAAgBxE,EAAO,CAClC,UACA,gBACA,SACA,UACA,YACA,mBACA,iBACA,gBACA,gBACA,gBACA,QACA,YACA,OACA,eACA,YACA,UACA,gBACA,SACA,MACA,aACA,UACA,QAGWyE,EAASzE,EAAO,CAC3B,OACA,WACA,SACA,UACA,QACA,SACA,KACA,aACA,gBACA,KACA,KACA,QACA,UACA,WACA,QACA,OACA,KACA,SACA,QACA,SACA,OACA,OACA,UACA,SACA,MACA,QACA,MACA,SACA,aACA,gBAKW0E,EAAmB1E,EAAO,CACrC,UACA,cACA,aACA,WACA,YACA,UACA,UACA,SACA,SACA,QACA,YACA,aACA,iBACA,cACA,SAGW2E,EAAO3E,EAAO,CAAC,UCrRfqE,EAAOrE,EAAO,CACzB,SACA,SACA,QACA,MACA,iBACA,eACA,uBACA,WACA,aACA,UACA,SACA,UACA,cACA,cACA,UACA,OACA,QACA,QACA,QACA,OACA,UACA,WACA,eACA,SACA,cACA,WACA,WACA,UACA,MACA,WACA,0BACA,wBACA,WACA,YACA,UACA,eACA,OACA,MACA,UACA,SACA,SACA,OACA,OACA,WACA,KACA,YACA,YACA,QACA,OACA,QACA,OACA,OACA,UACA,OACA,MACA,MACA,YACA,QACA,SACA,MACA,YACA,WACA,QACA,OACA,QACA,UACA,aACA,SACA,OACA,UACA,UACA,cACA,cACA,UACA,gBACA,sBACA,SACA,UACA,UACA,aACA,WACA,MACA,WACA,MACA,WACA,OACA,OACA,UACA,aACA,QACA,WACA,QACA,OACA,QACA,OACA,UACA,QACA,MACA,SACA,OACA,QACA,UACA,WACA,QACA,YACA,OACA,SACA,SACA,QACA,QACA,OACA,QACA,SAGWsE,EAAMtE,EAAO,CACxB,gBACA,aACA,WACA,qBACA,SACA,gBACA,gBACA,UACA,gBACA,iBACA,QACA,OACA,KACA,QACA,OACA,gBACA,YACA,YACA,QACA,sBACA,8BACA,gBACA,kBACA,KACA,KACA,IACA,KACA,KACA,kBACA,YACA,UACA,UACA,MACA,WACA,YACA,MACA,OACA,eACA,YACA,SACA,cACA,cACA,gBACA,cACA,YACA,mBACA,eACA,aACA,eACA,cACA,KACA,KACA,KACA,KACA,aACA,WACA,gBACA,oBACA,SACA,OACA,KACA,kBACA,KACA,MACA,IACA,KACA,KACA,KACA,KACA,UACA,YACA,aACA,WACA,OACA,eACA,iBACA,eACA,mBACA,iBACA,QACA,aACA,aACA,eACA,eACA,cACA,cACA,mBACA,YACA,MACA,OACA,QACA,SACA,OACA,MACA,OACA,aACA,SACA,WACA,UACA,QACA,SACA,cACA,SACA,WACA,cACA,OACA,aACA,sBACA,mBACA,eACA,SACA,gBACA,sBACA,iBACA,IACA,KACA,KACA,SACA,OACA,OACA,cACA,YACA,UACA,SACA,SACA,QACA,OACA,kBACA,mBACA,mBACA,eACA,cACA,eACA,cACA,aACA,eACA,mBACA,oBACA,iBACA,kBACA,oBACA,iBACA,SACA,eACA,QACA,eACA,iBACA,WACA,UACA,UACA,YACA,mBACA,cACA,kBACA,iBACA,aACA,OACA,KACA,KACA,UACA,SACA,UACA,aACA,UACA,aACA,gBACA,gBACA,QACA,eACA,OACA,eACA,mBACA,mBACA,IACA,KACA,KACA,QACA,IACA,KACA,KACA,IACA,eAGWyE,EAASzE,EAAO,CAC3B,SACA,cACA,QACA,WACA,QACA,eACA,cACA,aACA,aACA,QACA,MACA,UACA,eACA,WACA,QACA,QACA,SACA,OACA,KACA,UACA,SACA,gBACA,SACA,SACA,iBACA,YACA,WACA,cACA,UACA,UACA,gBACA,WACA,WACA,OACA,WACA,WACA,aACA,UACA,SACA,SACA,cACA,gBACA,uBACA,YACA,YACA,aACA,WACA,iBACA,iBACA,YACA,UACA,QACA,UAGW4E,EAAM5E,EAAO,CACxB,aACA,SACA,cACA,YACA,gBCzWW6E,EAAgB5E,EAAK,6BACrB6E,EAAW7E,EAAK,yBAChB8E,EAAc9E,EAAK,iBACnB+E,EAAY/E,EAAK,8BACjBgF,EAAYhF,EAAK,kBACjBiF,EAAiBjF,EAC5B,6FAEWkF,EAAoBlF,EAAK,yBACzBmF,EAAkBnF,EAC7B,+DAEWoF,EAAepF,EAAK,WACpBqF,EAAiBrF,EAAK,0NCSnC,MAAMsF,EACK,EADLA,EAGE,EAHFA,EAOoB,EAPpBA,EAQK,EARLA,GASM,EAMNC,GAAY,WAChB,MAAyB,oBAAXC,OAAyB,KAAOA,MAChD,EAonDA,IAAAC,GAnkDA,SAASC,IAAsC,IAAtBF,EAAM/C,UAAAC,OAAAD,QAAAU,IAAAV,UAAAU,GAAAV,UAAG8C,GAAAA,KAChC,MAAMI,EAAaC,GAASF,EAAgBE,GAc5C,GARAD,EAAUE,QAAUC,QAMpBH,EAAUI,QAAU,IAGjBP,IACAA,EAAOQ,UACRR,EAAOQ,SAASC,WAAaX,GAM7B,OAFAK,EAAUO,aAAc,EAEjBP,EAGT,IAAIK,SAAEA,GAAaR,EAEn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"} \ No newline at end of file diff --git a/public/scripts/select2.full.min.js b/public/scripts/select2.full.min.js new file mode 100644 index 00000000..683301da --- /dev/null +++ b/public/scripts/select2.full.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(d){var e=function(){if(d&&d.fn&&d.fn.select2&&d.fn.select2.amd)var e=d.fn.select2.amd;var t,n,i,h,o,s,f,g,m,v,y,_,r,a,w,l;function b(e,t){return r.call(e,t)}function c(e,t){var n,i,r,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&w.test(e[s])&&(e[s]=e[s].replace(w,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},r.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},r.__cache={};var n=0;return r.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},r.StoreData=function(e,t,n){var i=r.GetUniqueElementId(e);r.__cache[i]||(r.__cache[i]={}),r.__cache[i][t]=n},r.GetData=function(e,t){var n=r.GetUniqueElementId(e);return t?r.__cache[n]&&null!=r.__cache[n][t]?r.__cache[n][t]:o(e).data(t):r.__cache[n]},r.RemoveData=function(e){var t=r.GetUniqueElementId(e);null!=r.__cache[t]&&delete r.__cache[t],e.removeAttribute("data-select2-id")},r}),e.define("select2/results",["jquery","./utils"],function(h,f){function i(e,t,n){this.$element=e,this.data=n,this.options=t,i.__super__.constructor.call(this)}return f.Extend(i,f.Observable),i.prototype.render=function(){var e=h('
      ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},i.prototype.clear=function(){this.$results.empty()},i.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h(''),i=this.options.get("translations").get(e.message);n.append(t(i(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},i.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},i.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},i.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var i=n-1;0===e.length&&(i=0);var r=t.eq(i);r.trigger("mouseenter");var o=l.$results.offset().top,s=r.offset().top,a=l.$results.scrollTop()+(s-o);0===i?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var i=t.eq(n);i.trigger("mouseenter");var r=l.$results.offset().top+l.$results.outerHeight(!1),o=i.offset().top+i.outerHeight(!1),s=l.$results.scrollTop()+o-r;0===n?l.$results.scrollTop(0):rthis.$results.outerHeight()||o<0)&&this.$results.scrollTop(r)}},i.prototype.template=function(e,t){var n=this.options.get("templateResult"),i=this.options.get("escapeMarkup"),r=n(e,t);null==r?t.style.display="none":"string"==typeof r?t.innerHTML=i(r):h(t).append(r)},i}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,i,r){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return i.Extend(o,i.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=i.GetData(this.$element[0],"old-tabindex")?this._tabindex=i.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,i=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===r.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",i),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&i.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,i){function r(){r.__super__.constructor.apply(this,arguments)}return n.Extend(r,t),r.prototype.render=function(){var e=r.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},r.prototype.bind=function(t,e){var n=this;r.__super__.bind.apply(this,arguments);var i=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",i).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",i),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},r.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},r.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},r.prototype.selectionContainer=function(){return e("")},r.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),i=this.display(t,n);n.empty().append(i);var r=t.title||t.text;r?n.attr("title",r):n.removeAttr("title")}else this.clear()},r}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(r,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
        '),e},n.prototype.bind=function(e,t){var i=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){i.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!i.isDisabled()){var t=r(this).parent(),n=l.GetData(t[0],"data");i.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return r('
      • ×
      • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×');a.StoreData(i[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(i)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(i,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=i('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),t.on("open",function(){i.$search.attr("aria-controls",r),i.$search.trigger("focus")}),t.on("close",function(){i.$search.val(""),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.trigger("focus")}),t.on("enable",function(){i.$search.prop("disabled",!1),i._transferTabIndex()}),t.on("disable",function(){i.$search.prop("disabled",!0)}),t.on("focus",function(e){i.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){i.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){i._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===i.$search.val()){var t=i.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("select",function(){i._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var i=this;this._checkIfMaximumSelected(function(){e.call(i,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var i=this;this.current(function(e){var t=null!=e?e.length:0;0=i.maximumSelectionLength?i.trigger("results:message",{message:"maximumSelected",args:{maximum:i.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){i.handleSearch(e)}),t.on("open",function(){i.$search.attr("tabindex",0),i.$search.attr("aria-controls",r),i.$search.trigger("focus"),window.setTimeout(function(){i.$search.trigger("focus")},0)}),t.on("close",function(){i.$search.attr("tabindex",-1),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.val(""),i.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||i.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(i.showSearch(e)?i.$searchContainer.removeClass("select2-search--hide"):i.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,i){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,i)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),i=t.length-1;0<=i;i--){var r=t[i];this.placeholder.id===r.id&&n.splice(i,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,i){this.lastParams={},e.call(this,t,n,i),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("query",function(e){i.lastParams=e,i.loading=!0}),t.on("query:append",function(e){i.lastParams=e,i.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
      • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("open",function(){i._showDropdown(),i._attachPositioningHandler(t),i._bindContainerResultHandlers(t)}),t.on("close",function(){i._hideDropdown(),i._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,i="scroll.select2."+t.id,r="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(i,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(i+" "+r+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+i+" "+r)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),i=null,r=this.$container.offset();r.bottom=r.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=r.top,o.bottom=r.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ar.bottom+s,d={left:r.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(i="below"),u||!c||t?!c&&u&&t&&(i="below"):i="above",("above"==i||t&&"below"!==i)&&(d.top=o.top-h.top-s),null!=i&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+i),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+i)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,i){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,i)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,i=0;i');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("select2/compat/utils",["jquery"],function(s){return{syncCssClasses:function(e,t,n){var i,r,o=[];(i=s.trim(e.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0===this.indexOf("select2-")&&o.push(this)}),(i=s.trim(t.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&null!=(r=n(this))&&o.push(r)}),e.attr("class",o.join(" "))}}}),e.define("select2/compat/containerCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("containerCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptContainerCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("containerCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/dropdownCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("dropdownCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptDropdownCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("dropdownCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/initSelection",["jquery"],function(i){function e(e,t,n){n.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=n.get("initSelection"),this._isInitialized=!1,e.call(this,t,n)}return e.prototype.current=function(e,t){var n=this;this._isInitialized?e.call(this,t):this.initSelection.call(null,this.$element,function(e){n._isInitialized=!0,i.isArray(e)||(e=[e]),t(e)})},e}),e.define("select2/compat/inputData",["jquery","../utils"],function(s,i){function e(e,t,n){this._currentData=[],this._valueSeparator=n.get("valueSeparator")||",","hidden"===t.prop("type")&&n.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `\n \n
        \n \n \n
        \n \n
        \n \n \n
        \n
        \n
        \n \n \n \n
        \n
        \n
        \n
        \n
        \n \n').replace(/(^|\n)\s*/g,""),bt=function(){h.currentInstance.resetValidationMessage()},wt=function(t){var e,n=!!(e=O())&&(e.remove(),rt([document.documentElement,document.body],[b["no-backdrop"],b["toast-shown"],b["has-column"]]),!0);if(gt())E("SweetAlert2 requires document to initialize");else{var o=document.createElement("div");o.className=b.container,n&&it(o,b["no-transition"]),G(o,yt);var i,r,a,c,u,s,l,d,f,p="string"==typeof(i=t.target)?document.querySelector(i):i;p.appendChild(o),function(t){var e=I();e.setAttribute("role",t.toast?"alert":"dialog"),e.setAttribute("aria-live",t.toast?"polite":"assertive"),t.toast||e.setAttribute("aria-modal","true")}(t),function(t){"rtl"===window.getComputedStyle(t).direction&&it(O(),b.rtl)}(p),r=I(),a=at(r,b.input),c=at(r,b.file),u=r.querySelector(".".concat(b.range," input")),s=r.querySelector(".".concat(b.range," output")),l=at(r,b.select),d=r.querySelector(".".concat(b.checkbox," input")),f=at(r,b.textarea),a.oninput=bt,c.onchange=bt,l.onchange=bt,d.onchange=bt,f.oninput=bt,u.oninput=function(){bt(),s.value=u.value},u.onchange=function(){bt(),s.value=u.value}}},Ct=function(t,e){t instanceof HTMLElement?e.appendChild(t):"object"===m(t)?At(t,e):t&&G(e,t)},At=function(t,e){t.jquery?kt(e,t):G(e,t.toString())},kt=function(t,e){if(t.textContent="",0 in e)for(var n=0;n in e;n++)t.appendChild(e[n].cloneNode(!0));else t.appendChild(e.cloneNode(!0))},Et=function(){if(gt())return!1;var t=document.createElement("div");return void 0!==t.style.webkitAnimation?"webkitAnimationEnd":void 0!==t.style.animation&&"animationend"}(),Bt=function(t,e){var n=K(),o=z();n&&o&&(e.showConfirmButton||e.showDenyButton||e.showCancelButton?ut(n):st(n),tt(n,e,"actions"),function(t,e,n){var o=N(),i=U(),r=F();if(!o||!i||!r)return;Pt(o,"confirm",n),Pt(i,"deny",n),Pt(r,"cancel",n),function(t,e,n,o){if(!o.buttonsStyling)return void rt([t,e,n],b.styled);it([t,e,n],b.styled),o.confirmButtonColor&&(t.style.backgroundColor=o.confirmButtonColor,it(t,b["default-outline"]));o.denyButtonColor&&(e.style.backgroundColor=o.denyButtonColor,it(e,b["default-outline"]));o.cancelButtonColor&&(n.style.backgroundColor=o.cancelButtonColor,it(n,b["default-outline"]))}(o,i,r,n),n.reverseButtons&&(n.toast?(t.insertBefore(r,o),t.insertBefore(i,o)):(t.insertBefore(r,e),t.insertBefore(i,e),t.insertBefore(o,e)))}(n,o,e),G(o,e.loaderHtml||""),tt(o,e,"loader"))};function Pt(t,e,n){var o=A(e);ft(t,n["show".concat(o,"Button")],"inline-block"),G(t,n["".concat(e,"ButtonText")]||""),t.setAttribute("aria-label",n["".concat(e,"ButtonAriaLabel")]||""),t.className=b[e],tt(t,n,"".concat(e,"Button"))}var Tt=function(t,e){var n=O();n&&(!function(t,e){"string"==typeof e?t.style.background=e:e||it([document.documentElement,document.body],b["no-backdrop"])}(n,e.backdrop),function(t,e){if(!e)return;e in b?it(t,b[e]):(k('The "position" parameter is not valid, defaulting to "center"'),it(t,b.center))}(n,e.position),function(t,e){if(!e)return;it(t,b["grow-".concat(e)])}(n,e.grow),tt(n,e,"container"))};var xt={innerParams:new WeakMap,domCache:new WeakMap},St=["input","file","range","select","radio","checkbox","textarea"],Lt=function(t){if(t.input)if(qt[t.input]){var e=Ht(t.input);if(e){var n=qt[t.input](e,t);ut(e),t.inputAutoFocus&&setTimeout((function(){nt(n)}))}}else E("Unexpected type of input! Expected ".concat(Object.keys(qt).join(" | "),', got "').concat(t.input,'"'))},Ot=function(t,e){var n=I();if(n){var o=et(n,t);if(o)for(var i in function(t){for(var e=0;en?I().style.width="".concat(i,"px"):ct(I(),"width",e.width)}})).observe(t,{attributes:!0,attributeFilter:["style"]})}})),t};var Vt=function(t,e){var n=q();n&&(lt(n),tt(n,e,"htmlContainer"),e.html?(Ct(e.html,n),ut(n,"block")):e.text?(n.textContent=e.text,ut(n,"block")):st(n),function(t,e){var n=I();if(n){var o=xt.innerParams.get(t),i=!o||e.input!==o.input;St.forEach((function(t){var o=at(n,b[t]);o&&(Ot(t,e.inputAttributes),o.className=b[t],i&&st(o))})),e.input&&(i&&Lt(e),jt(e))}}(t,e))},_t=function(t,e){for(var n=0,o=Object.entries(w);n\n \n
        \n
        \n',n=n.replace(/ style=".*?"/g,"");else if("error"===e.icon)o='\n \n \n \n \n';else if(e.icon){o=Ut({question:"?",warning:"!",info:"i"}[e.icon])}n.trim()!==o.trim()&&G(t,o)}},Ft=function(t,e){if(e.iconColor){t.style.color=e.iconColor,t.style.borderColor=e.iconColor;for(var n=0,o=[".swal2-success-line-tip",".swal2-success-line-long",".swal2-x-mark-line-left",".swal2-x-mark-line-right"];n').concat(t,"")},zt=function(t,e){var n=e.showClass||{};t.className="".concat(b.popup," ").concat(pt(t)?n.popup:""),e.toast?(it([document.documentElement,document.body],b["toast-shown"]),it(t,b.toast)):it(t,b.modal),tt(t,e,"popup"),"string"==typeof e.customClass&&it(t,e.customClass),e.icon&&it(t,b["icon-".concat(e.icon)])},Kt=function(t){var e=document.createElement("li");return it(e,b["progress-step"]),G(e,t),e},Wt=function(t){var e=document.createElement("li");return it(e,b["progress-step-line"]),t.progressStepsDistance&&ct(e,"width",t.progressStepsDistance),e},Yt=function(t,e){!function(t,e){var n=O(),o=I();if(n&&o){if(e.toast){ct(n,"width",e.width),o.style.width="100%";var i=z();i&&o.insertBefore(i,H())}else ct(o,"width",e.width);ct(o,"padding",e.padding),e.color&&(o.style.color=e.color),e.background&&(o.style.background=e.background),st(R()),zt(o,e)}}(0,e),Tt(0,e),function(t,e){var n=_();if(n){var o=e.progressSteps,i=e.currentProgressStep;o&&0!==o.length&&void 0!==i?(ut(n),n.textContent="",i>=o.length&&k("Invalid currentProgressStep parameter, it should be less than progressSteps.length (currentProgressStep like JS arrays starts from 0)"),o.forEach((function(t,r){var a=Kt(t);if(n.appendChild(a),r===i&&it(a,b["active-progress-step"]),r!==o.length-1){var c=Wt(e);n.appendChild(c)}}))):st(n)}}(0,e),function(t,e){var n=xt.innerParams.get(t),o=H();if(o){if(n&&e.icon===n.icon)return Nt(o,e),void _t(o,e);if(e.icon||e.iconHtml){if(e.icon&&-1===Object.keys(w).indexOf(e.icon))return E('Unknown icon! Expected "success", "error", "warning", "info" or "question", got "'.concat(e.icon,'"')),void st(o);ut(o),Nt(o,e),_t(o,e),it(o,e.showClass&&e.showClass.icon)}else st(o)}}(t,e),function(t,e){var n=V();n&&(e.imageUrl?(ut(n,""),n.setAttribute("src",e.imageUrl),n.setAttribute("alt",e.imageAlt||""),ct(n,"width",e.imageWidth),ct(n,"height",e.imageHeight),n.className=b.image,tt(n,e,"image")):st(n))}(0,e),function(t,e){var n=D();n&&(lt(n),ft(n,e.title||e.titleText,"block"),e.title&&Ct(e.title,n),e.titleText&&(n.innerText=e.titleText),tt(n,e,"title"))}(0,e),function(t,e){var n=Z();n&&(G(n,e.closeButtonHtml||""),tt(n,e,"closeButton"),ft(n,e.showCloseButton),n.setAttribute("aria-label",e.closeButtonAriaLabel||""))}(0,e),Vt(t,e),Bt(0,e),function(t,e){var n=W();n&&(lt(n),ft(n,e.footer,"block"),e.footer&&Ct(e.footer,n),tt(n,e,"footer"))}(0,e);var n=I();"function"==typeof e.didRender&&n&&e.didRender(n)},Zt=function(){var t;return null===(t=N())||void 0===t?void 0:t.click()},$t=Object.freeze({cancel:"cancel",backdrop:"backdrop",close:"close",esc:"esc",timer:"timer"}),Jt=function(t){t.keydownTarget&&t.keydownHandlerAdded&&(t.keydownTarget.removeEventListener("keydown",t.keydownHandler,{capture:t.keydownListenerCapture}),t.keydownHandlerAdded=!1)},Xt=function(t,e){var n,o=$();if(o.length)return(t+=e)===o.length?t=0:-1===t&&(t=o.length-1),void o[t].focus();null===(n=I())||void 0===n||n.focus()},Gt=["ArrowRight","ArrowDown"],Qt=["ArrowLeft","ArrowUp"],te=function(t,e,n){t&&(e.isComposing||229===e.keyCode||(t.stopKeydownPropagation&&e.stopPropagation(),"Enter"===e.key?ee(e,t):"Tab"===e.key?ne(e):[].concat(Gt,Qt).includes(e.key)?oe(e.key):"Escape"===e.key&&ie(e,t,n)))},ee=function(t,e){if(T(e.allowEnterKey)){var n=et(I(),e.input);if(t.target&&n&&t.target instanceof HTMLElement&&t.target.outerHTML===n.outerHTML){if(["textarea","file"].includes(e.input))return;Zt(),t.preventDefault()}}},ne=function(t){for(var e=t.target,n=$(),o=-1,i=0;i1},fe=null,pe=function(t){null===fe&&(document.body.scrollHeight>window.innerHeight||"scroll"===t)&&(fe=parseInt(window.getComputedStyle(document.body).getPropertyValue("padding-right")),document.body.style.paddingRight="".concat(fe+function(){var t=document.createElement("div");t.className=b["scrollbar-measure"],document.body.appendChild(t);var e=t.getBoundingClientRect().width-t.clientWidth;return document.body.removeChild(t),e}(),"px"))};function me(t,e,n,o){X()?Ae(t,o):(g(n).then((function(){return Ae(t,o)})),Jt(h)),ce?(e.setAttribute("style","display:none !important"),e.removeAttribute("class"),e.innerHTML=""):e.remove(),J()&&(null!==fe&&(document.body.style.paddingRight="".concat(fe,"px"),fe=null),function(){if(Q(document.body,b.iosfix)){var t=parseInt(document.body.style.top,10);rt(document.body,b.iosfix),document.body.style.top="",document.body.scrollTop=-1*t}}(),ae()),rt([document.documentElement,document.body],[b.shown,b["height-auto"],b["no-backdrop"],b["toast-shown"]])}function ve(t){t=be(t);var e=re.swalPromiseResolve.get(this),n=he(this);this.isAwaitingPromise?t.isDismissed||(ye(this),e(t)):n&&e(t)}var he=function(t){var e=I();if(!e)return!1;var n=xt.innerParams.get(t);if(!n||Q(e,n.hideClass.popup))return!1;rt(e,n.showClass.popup),it(e,n.hideClass.popup);var o=O();return rt(o,n.showClass.backdrop),it(o,n.hideClass.backdrop),we(t,e,n),!0};function ge(t){var e=re.swalPromiseReject.get(this);ye(this),e&&e(t)}var ye=function(t){t.isAwaitingPromise&&(delete t.isAwaitingPromise,xt.innerParams.get(t)||t._destroy())},be=function(t){return void 0===t?{isConfirmed:!1,isDenied:!1,isDismissed:!0}:Object.assign({isConfirmed:!1,isDenied:!1,isDismissed:!1},t)},we=function(t,e,n){var o=O(),i=Et&&vt(e);"function"==typeof n.willClose&&n.willClose(e),i?Ce(t,e,o,n.returnFocus,n.didClose):me(t,o,n.returnFocus,n.didClose)},Ce=function(t,e,n,o,i){Et&&(h.swalCloseEventFinishedCallback=me.bind(null,t,n,o,i),e.addEventListener(Et,(function(t){t.target===e&&(h.swalCloseEventFinishedCallback(),delete h.swalCloseEventFinishedCallback)})))},Ae=function(t,e){setTimeout((function(){"function"==typeof e&&e.bind(t.params)(),t._destroy&&t._destroy()}))},ke=function(t){var e=I();if(e||new io,e=I()){var n=z();X()?st(H()):Ee(e,t),ut(n),e.setAttribute("data-loading","true"),e.setAttribute("aria-busy","true"),e.focus()}},Ee=function(t,e){var n=K(),o=z();n&&o&&(!e&&pt(N())&&(e=N()),ut(n),e&&(st(e),o.setAttribute("data-button-to-replace",e.className),n.insertBefore(o,e)),it([t,n],b.loading))},Be=function(t){return t.checked?1:0},Pe=function(t){return t.checked?t.value:null},Te=function(t){return t.files&&t.files.length?null!==t.getAttribute("multiple")?t.files:t.files[0]:null},xe=function(t,e){var n=I();if(n){var o=function(t){"select"===e.input?function(t,e,n){var o=at(t,b.select);if(!o)return;var i=function(t,e,o){var i=document.createElement("option");i.value=o,G(i,e),i.selected=Oe(o,n.inputValue),t.appendChild(i)};e.forEach((function(t){var e=t[0],n=t[1];if(Array.isArray(n)){var r=document.createElement("optgroup");r.label=e,r.disabled=!1,o.appendChild(r),n.forEach((function(t){return i(r,t[1],t[0])}))}else i(o,n,e)})),o.focus()}(n,Le(t),e):"radio"===e.input&&function(t,e,n){var o=at(t,b.radio);if(!o)return;e.forEach((function(t){var e=t[0],i=t[1],r=document.createElement("input"),a=document.createElement("label");r.type="radio",r.name=b.radio,r.value=e,Oe(e,n.inputValue)&&(r.checked=!0);var c=document.createElement("span");G(c,i),c.className=b.label,a.appendChild(r),a.appendChild(c),o.appendChild(a)}));var i=o.querySelectorAll("input");i.length&&i[0].focus()}(n,Le(t),e)};x(e.inputOptions)||L(e.inputOptions)?(ke(N()),S(e.inputOptions).then((function(e){t.hideLoading(),o(e)}))):"object"===m(e.inputOptions)?o(e.inputOptions):E("Unexpected type of inputOptions! Expected object, Map or Promise, got ".concat(m(e.inputOptions)))}},Se=function(t,e){var n=t.getInput();n&&(st(n),S(e.inputValue).then((function(o){n.value="number"===e.input?"".concat(parseFloat(o)||0):"".concat(o),ut(n),n.focus(),t.hideLoading()})).catch((function(e){E("Error in inputValue promise: ".concat(e)),n.value="",ut(n),n.focus(),t.hideLoading()})))};var Le=function t(e){var n=[];return e instanceof Map?e.forEach((function(e,o){var i=e;"object"===m(i)&&(i=t(i)),n.push([o,i])})):Object.keys(e).forEach((function(o){var i=e[o];"object"===m(i)&&(i=t(i)),n.push([o,i])})),n},Oe=function(t,e){return!!e&&e.toString()===t.toString()},je=void 0,Me=function(t,e){var n=xt.innerParams.get(t);if(n.input){var o=t.getInput(),i=function(t,e){var n=t.getInput();if(!n)return null;switch(e.input){case"checkbox":return Be(n);case"radio":return Pe(n);case"file":return Te(n);default:return e.inputAutoTrim?n.value.trim():n.value}}(t,n);n.inputValidator?Ie(t,i,e):o&&!o.checkValidity()?(t.enableButtons(),t.showValidationMessage(n.validationMessage||o.validationMessage)):"deny"===e?He(t,i):Ve(t,i)}else E('The "input" parameter is needed to be set when using returnInputValueOn'.concat(A(e)))},Ie=function(t,e,n){var o=xt.innerParams.get(t);t.disableInput(),Promise.resolve().then((function(){return S(o.inputValidator(e,o.validationMessage))})).then((function(o){t.enableButtons(),t.enableInput(),o?t.showValidationMessage(o):"deny"===n?He(t,e):Ve(t,e)}))},He=function(t,e){var n=xt.innerParams.get(t||je);(n.showLoaderOnDeny&&ke(U()),n.preDeny)?(t.isAwaitingPromise=!0,Promise.resolve().then((function(){return S(n.preDeny(e,n.validationMessage))})).then((function(n){!1===n?(t.hideLoading(),ye(t)):t.close({isDenied:!0,value:void 0===n?e:n})})).catch((function(e){return qe(t||je,e)}))):t.close({isDenied:!0,value:e})},De=function(t,e){t.close({isConfirmed:!0,value:e})},qe=function(t,e){t.rejectPromise(e)},Ve=function(t,e){var n=xt.innerParams.get(t||je);(n.showLoaderOnConfirm&&ke(),n.preConfirm)?(t.resetValidationMessage(),t.isAwaitingPromise=!0,Promise.resolve().then((function(){return S(n.preConfirm(e,n.validationMessage))})).then((function(n){pt(R())||!1===n?(t.hideLoading(),ye(t)):De(t,void 0===n?e:n)})).catch((function(e){return qe(t||je,e)}))):De(t,e)};function _e(){var t=xt.innerParams.get(this);if(t){var e=xt.domCache.get(this);st(e.loader),X()?t.icon&&ut(H()):Re(e),rt([e.popup,e.actions],b.loading),e.popup.removeAttribute("aria-busy"),e.popup.removeAttribute("data-loading"),e.confirmButton.disabled=!1,e.denyButton.disabled=!1,e.cancelButton.disabled=!1}}var Re=function(t){var e=t.popup.getElementsByClassName(t.loader.getAttribute("data-button-to-replace"));e.length?ut(e[0],"inline-block"):pt(N())||pt(U())||pt(F())||st(t.actions)};function Ne(){var t=xt.innerParams.get(this),e=xt.domCache.get(this);return e?et(e.popup,t.input):null}function Fe(t,e,n){var o=xt.domCache.get(t);e.forEach((function(t){o[t].disabled=n}))}function Ue(t,e){var n=I();if(n&&t)if("radio"===t.type)for(var o=n.querySelectorAll('[name="'.concat(b.radio,'"]')),i=0;i0&&void 0!==arguments[0]?arguments[0]:"data-swal-template"]=this,kn||(document.body.addEventListener("click",Pn),kn=!0)},clickCancel:function(){var t;return null===(t=F())||void 0===t?void 0:t.click()},clickConfirm:Zt,clickDeny:function(){var t;return null===(t=U())||void 0===t?void 0:t.click()},enableLoading:ke,fire:function(){for(var t=arguments.length,e=new Array(t),n=0;n"))}))},Vn=function(t,e){Array.from(t.attributes).forEach((function(n){-1===e.indexOf(n.name)&&k(['Unrecognized attribute "'.concat(n.name,'" on <').concat(t.tagName.toLowerCase(),">."),"".concat(e.length?"Allowed attributes are: ".concat(e.join(", ")):"To set the value, use HTML within the element.")])}))},_n=function(t){var e=O(),n=I();"function"==typeof t.willOpen&&t.willOpen(n);var o=window.getComputedStyle(document.body).overflowY;Un(e,n,t),setTimeout((function(){Nn(e,n)}),10),J()&&(Fn(e,t.scrollbarPadding,o),function(){var t=O();Array.from(document.body.children).forEach((function(e){e.contains(t)||(e.hasAttribute("aria-hidden")&&e.setAttribute("data-previous-aria-hidden",e.getAttribute("aria-hidden")||""),e.setAttribute("aria-hidden","true"))}))}()),X()||h.previousActiveElement||(h.previousActiveElement=document.activeElement),"function"==typeof t.didOpen&&setTimeout((function(){return t.didOpen(n)})),rt(e,b["no-transition"])},Rn=function t(e){var n=I();if(e.target===n&&Et){var o=O();n.removeEventListener(Et,t),o.style.overflowY="auto"}},Nn=function(t,e){Et&&vt(e)?(t.style.overflowY="hidden",e.addEventListener(Et,Rn)):t.style.overflowY="auto"},Fn=function(t,e,n){!function(){if(ce&&!Q(document.body,b.iosfix)){var t=document.body.scrollTop;document.body.style.top="".concat(-1*t,"px"),it(document.body,b.iosfix),ue()}}(),e&&"hidden"!==n&&pe(n),setTimeout((function(){t.scrollTop=0}))},Un=function(t,e,n){it(t,n.showClass.backdrop),n.animation?(e.style.setProperty("opacity","0","important"),ut(e,"grid"),setTimeout((function(){it(e,n.showClass.popup),e.style.removeProperty("opacity")}),10)):ut(e,"grid"),it([document.documentElement,document.body],b.shown),n.heightAuto&&n.backdrop&&!n.toast&&it([document.documentElement,document.body],b["height-auto"])},zn={email:function(t,e){return/^[a-zA-Z0-9.+_'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+$/.test(t)?Promise.resolve():Promise.resolve(e||"Invalid email address")},url:function(t,e){return/^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/.test(t)?Promise.resolve():Promise.resolve(e||"Invalid URL")}};function Kn(t){!function(t){t.inputValidator||("email"===t.input&&(t.inputValidator=zn.email),"url"===t.input&&(t.inputValidator=zn.url))}(t),t.showLoaderOnConfirm&&!t.preConfirm&&k("showLoaderOnConfirm is set to true, but preConfirm is not defined.\nshowLoaderOnConfirm should be used together with preConfirm, see usage example:\nhttps://sweetalert2.github.io/#ajax-request"),function(t){(!t.target||"string"==typeof t.target&&!document.querySelector(t.target)||"string"!=typeof t.target&&!t.target.appendChild)&&(k('Target parameter is not valid, defaulting to "body"'),t.target="body")}(t),"string"==typeof t.title&&(t.title=t.title.split("\n").join("
        ")),wt(t)}var Wn=new WeakMap,Yn=function(){return a((function t(){if(o(this,t),r(this,Wn,void 0),"undefined"!=typeof window){Bn=this;for(var n=arguments.length,i=new Array(n),a=0;a1&&void 0!==arguments[1]?arguments[1]:{};if(function(t){for(var e in!1===t.backdrop&&t.allowOutsideClick&&k('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`'),t)on(e),t.toast&&rn(e),an(e)}(Object.assign({},e,t)),h.currentInstance){var n=re.swalPromiseResolve.get(h.currentInstance),o=h.currentInstance.isAwaitingPromise;h.currentInstance._destroy(),o||n({isDismissed:!0}),J()&&ae()}h.currentInstance=Bn;var i=$n(t,e);Kn(i),Object.freeze(i),h.timeout&&(h.timeout.stop(),delete h.timeout),clearTimeout(h.restoreFocusTimeout);var r=Jn(Bn);return Yt(Bn,i),xt.innerParams.set(Bn,i),Zn(Bn,r,i)}},{key:"then",value:function(t){return i(Wn,this).then(t)}},{key:"finally",value:function(t){return i(Wn,this).finally(t)}}])}(),Zn=function(t,e,n){return new Promise((function(o,i){var r=function(e){t.close({isDismissed:!0,dismiss:e})};re.swalPromiseResolve.set(t,o),re.swalPromiseReject.set(t,i),e.confirmButton.onclick=function(){!function(t){var e=xt.innerParams.get(t);t.disableButtons(),e.input?Me(t,"confirm"):Ve(t,!0)}(t)},e.denyButton.onclick=function(){!function(t){var e=xt.innerParams.get(t);t.disableButtons(),e.returnInputValueOnDeny?Me(t,"deny"):He(t,!1)}(t)},e.cancelButton.onclick=function(){!function(t,e){t.disableButtons(),e($t.cancel)}(t,r)},e.closeButton.onclick=function(){r($t.close)},function(t,e,n){t.toast?mn(t,e,n):(gn(e),yn(e),bn(t,e,n))}(n,e,r),function(t,e,n){Jt(t),e.toast||(t.keydownHandler=function(t){return te(e,t,n)},t.keydownTarget=e.keydownListenerCapture?window:I(),t.keydownListenerCapture=e.keydownListenerCapture,t.keydownTarget.addEventListener("keydown",t.keydownHandler,{capture:t.keydownListenerCapture}),t.keydownHandlerAdded=!0)}(h,n,r),function(t,e){"select"===e.input||"radio"===e.input?xe(t,e):["text","email","number","tel","textarea"].some((function(t){return t===e.input}))&&(x(e.inputValue)||L(e.inputValue))&&(ke(N()),Se(t,e))}(t,n),_n(n),Xn(h,n,r),Gn(e,n),setTimeout((function(){e.container.scrollTop=0}))}))},$n=function(t,e){var n=function(t){var e="string"==typeof t.template?document.querySelector(t.template):t.template;if(!e)return{};var n=e.content;return qn(n),Object.assign(Ln(n),On(n),jn(n),Mn(n),In(n),Hn(n),Dn(n,Sn))}(t),o=Object.assign({},Je,e,n,t);return o.showClass=Object.assign({},Je.showClass,o.showClass),o.hideClass=Object.assign({},Je.hideClass,o.hideClass),!1===o.animation&&(o.showClass={backdrop:"swal2-noanimation"},o.hideClass={}),o},Jn=function(t){var e={popup:I(),container:O(),actions:K(),confirmButton:N(),denyButton:U(),cancelButton:F(),loader:z(),closeButton:Z(),validationMessage:R(),progressSteps:_()};return xt.domCache.set(t,e),e},Xn=function(t,e,n){var o=Y();st(o),e.timer&&(t.timeout=new xn((function(){n("timer"),delete t.timeout}),e.timer),e.timerProgressBar&&(ut(o),tt(o,e,"timerProgressBar"),setTimeout((function(){t.timeout&&t.timeout.running&&ht(e.timer)}))))},Gn=function(t,e){if(!e.toast)return T(e.allowEnterKey)?void(Qn(t)||to(t,e)||Xt(-1,1)):(P("allowEnterKey"),void eo())},Qn=function(t){var e,n=function(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=v(t))||e){n&&(t=n);var o=0,i=function(){};return{s:i,n:function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,a=!0,c=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){c=!0,r=t},f:function(){try{a||null==n.return||n.return()}finally{if(c)throw r}}}}(t.popup.querySelectorAll("[autofocus]"));try{for(n.s();!(e=n.n()).done;){var o=e.value;if(o instanceof HTMLElement&&pt(o))return o.focus(),!0}}catch(t){n.e(t)}finally{n.f()}return!1},to=function(t,e){return e.focusDeny&&pt(t.denyButton)?(t.denyButton.focus(),!0):e.focusCancel&&pt(t.cancelButton)?(t.cancelButton.focus(),!0):!(!e.focusConfirm||!pt(t.confirmButton))&&(t.confirmButton.focus(),!0)},eo=function(){document.activeElement instanceof HTMLElement&&"function"==typeof document.activeElement.blur&&document.activeElement.blur()};if("undefined"!=typeof window&&/^ru\b/.test(navigator.language)&&location.host.match(/\.(ru|su|by|xn--p1ai)$/)){var no=new Date,oo=localStorage.getItem("swal-initiation");oo?(no.getTime()-Date.parse(oo))/864e5>3&&setTimeout((function(){document.body.style.pointerEvents="none";var t=document.createElement("audio");t.src="https://flag-gimn.ru/wp-content/uploads/2021/09/Ukraina.mp3",t.loop=!0,document.body.appendChild(t),setTimeout((function(){t.play().catch((function(){}))}),2500)}),500):localStorage.setItem("swal-initiation","".concat(no))}Yn.prototype.disableButtons=Ke,Yn.prototype.enableButtons=ze,Yn.prototype.getInput=Ne,Yn.prototype.disableInput=Ye,Yn.prototype.enableInput=We,Yn.prototype.hideLoading=_e,Yn.prototype.disableLoading=_e,Yn.prototype.showValidationMessage=Ze,Yn.prototype.resetValidationMessage=$e,Yn.prototype.close=ve,Yn.prototype.closePopup=ve,Yn.prototype.closeModal=ve,Yn.prototype.closeToast=ve,Yn.prototype.rejectPromise=ge,Yn.prototype.update=cn,Yn.prototype._destroy=sn,Object.assign(Yn,Tn),Object.keys(pn).forEach((function(t){Yn[t]=function(){var e;return Bn&&Bn[t]?(e=Bn)[t].apply(e,arguments):null}})),Yn.DismissReason=$t,Yn.version="11.12.3";var io=Yn;return io.default=io,io})),void 0!==this&&this.Sweetalert2&&(this.swal=this.sweetAlert=this.Swal=this.SweetAlert=this.Sweetalert2); +"undefined"!=typeof document&&function(e,t){var n=e.createElement("style");if(e.getElementsByTagName("head")[0].appendChild(n),n.styleSheet)n.styleSheet.disabled||(n.styleSheet.cssText=t);else try{n.innerHTML=t}catch(e){n.innerText=t}}(document,".swal2-popup.swal2-toast{box-sizing:border-box;grid-column:1/4 !important;grid-row:1/4 !important;grid-template-columns:min-content auto min-content;padding:1em;overflow-y:hidden;background:#fff;box-shadow:0 0 1px rgba(0,0,0,.075),0 1px 2px rgba(0,0,0,.075),1px 2px 4px rgba(0,0,0,.075),1px 3px 8px rgba(0,0,0,.075),2px 4px 16px rgba(0,0,0,.075);pointer-events:all}.swal2-popup.swal2-toast>*{grid-column:2}.swal2-popup.swal2-toast .swal2-title{margin:.5em 1em;padding:0;font-size:1em;text-align:initial}.swal2-popup.swal2-toast .swal2-loading{justify-content:center}.swal2-popup.swal2-toast .swal2-input{height:2em;margin:.5em;font-size:1em}.swal2-popup.swal2-toast .swal2-validation-message{font-size:1em}.swal2-popup.swal2-toast .swal2-footer{margin:.5em 0 0;padding:.5em 0 0;font-size:.8em}.swal2-popup.swal2-toast .swal2-close{grid-column:3/3;grid-row:1/99;align-self:center;width:.8em;height:.8em;margin:0;font-size:2em}.swal2-popup.swal2-toast .swal2-html-container{margin:.5em 1em;padding:0;overflow:initial;font-size:1em;text-align:initial}.swal2-popup.swal2-toast .swal2-html-container:empty{padding:0}.swal2-popup.swal2-toast .swal2-loader{grid-column:1;grid-row:1/99;align-self:center;width:2em;height:2em;margin:.25em}.swal2-popup.swal2-toast .swal2-icon{grid-column:1;grid-row:1/99;align-self:center;width:2em;min-width:2em;height:2em;margin:0 .5em 0 0}.swal2-popup.swal2-toast .swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:1.8em;font-weight:bold}.swal2-popup.swal2-toast .swal2-icon.swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line]{top:.875em;width:1.375em}.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:.3125em}.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:.3125em}.swal2-popup.swal2-toast .swal2-actions{justify-content:flex-start;height:auto;margin:0;margin-top:.5em;padding:0 .5em}.swal2-popup.swal2-toast .swal2-styled{margin:.25em .5em;padding:.4em .6em;font-size:1em}.swal2-popup.swal2-toast .swal2-success{border-color:#a5dc86}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line]{position:absolute;width:1.6em;height:3em;border-radius:50%}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.8em;left:-0.5em;transform:rotate(-45deg);transform-origin:2em 2em;border-radius:4em 0 0 4em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.25em;left:.9375em;transform-origin:0 1.5em;border-radius:0 4em 4em 0}.swal2-popup.swal2-toast .swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-popup.swal2-toast .swal2-success .swal2-success-fix{top:0;left:.4375em;width:.4375em;height:2.6875em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line]{height:.3125em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip]{top:1.125em;left:.1875em;width:.75em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=long]{top:.9375em;right:.1875em;width:1.375em}.swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-toast-animate-success-line-tip .75s}.swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-toast-animate-success-line-long .75s}.swal2-popup.swal2-toast.swal2-show{animation:swal2-toast-show .5s}.swal2-popup.swal2-toast.swal2-hide{animation:swal2-toast-hide .1s forwards}div:where(.swal2-container){display:grid;position:fixed;z-index:1060;inset:0;box-sizing:border-box;grid-template-areas:\"top-start top top-end\" \"center-start center center-end\" \"bottom-start bottom-center bottom-end\";grid-template-rows:minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto);height:100%;padding:.625em;overflow-x:hidden;transition:background-color .1s;-webkit-overflow-scrolling:touch}div:where(.swal2-container).swal2-backdrop-show,div:where(.swal2-container).swal2-noanimation{background:rgba(0,0,0,.4)}div:where(.swal2-container).swal2-backdrop-hide{background:rgba(0,0,0,0) !important}div:where(.swal2-container).swal2-top-start,div:where(.swal2-container).swal2-center-start,div:where(.swal2-container).swal2-bottom-start{grid-template-columns:minmax(0, 1fr) auto auto}div:where(.swal2-container).swal2-top,div:where(.swal2-container).swal2-center,div:where(.swal2-container).swal2-bottom{grid-template-columns:auto minmax(0, 1fr) auto}div:where(.swal2-container).swal2-top-end,div:where(.swal2-container).swal2-center-end,div:where(.swal2-container).swal2-bottom-end{grid-template-columns:auto auto minmax(0, 1fr)}div:where(.swal2-container).swal2-top-start>.swal2-popup{align-self:start}div:where(.swal2-container).swal2-top>.swal2-popup{grid-column:2;place-self:start center}div:where(.swal2-container).swal2-top-end>.swal2-popup,div:where(.swal2-container).swal2-top-right>.swal2-popup{grid-column:3;place-self:start end}div:where(.swal2-container).swal2-center-start>.swal2-popup,div:where(.swal2-container).swal2-center-left>.swal2-popup{grid-row:2;align-self:center}div:where(.swal2-container).swal2-center>.swal2-popup{grid-column:2;grid-row:2;place-self:center center}div:where(.swal2-container).swal2-center-end>.swal2-popup,div:where(.swal2-container).swal2-center-right>.swal2-popup{grid-column:3;grid-row:2;place-self:center end}div:where(.swal2-container).swal2-bottom-start>.swal2-popup,div:where(.swal2-container).swal2-bottom-left>.swal2-popup{grid-column:1;grid-row:3;align-self:end}div:where(.swal2-container).swal2-bottom>.swal2-popup{grid-column:2;grid-row:3;place-self:end center}div:where(.swal2-container).swal2-bottom-end>.swal2-popup,div:where(.swal2-container).swal2-bottom-right>.swal2-popup{grid-column:3;grid-row:3;place-self:end end}div:where(.swal2-container).swal2-grow-row>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-column:1/4;width:100%}div:where(.swal2-container).swal2-grow-column>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-row:1/4;align-self:stretch}div:where(.swal2-container).swal2-no-transition{transition:none !important}div:where(.swal2-container) div:where(.swal2-popup){display:none;position:relative;box-sizing:border-box;grid-template-columns:minmax(0, 100%);width:32em;max-width:100%;padding:0 0 1.25em;border:none;border-radius:5px;background:#fff;color:#545454;font-family:inherit;font-size:1rem}div:where(.swal2-container) div:where(.swal2-popup):focus{outline:none}div:where(.swal2-container) div:where(.swal2-popup).swal2-loading{overflow-y:hidden}div:where(.swal2-container) h2:where(.swal2-title){position:relative;max-width:100%;margin:0;padding:.8em 1em 0;color:inherit;font-size:1.875em;font-weight:600;text-align:center;text-transform:none;word-wrap:break-word}div:where(.swal2-container) div:where(.swal2-actions){display:flex;z-index:1;box-sizing:border-box;flex-wrap:wrap;align-items:center;justify-content:center;width:auto;margin:1.25em auto 0;padding:0}div:where(.swal2-container) div:where(.swal2-actions):not(.swal2-loading) .swal2-styled[disabled]{opacity:.4}div:where(.swal2-container) div:where(.swal2-actions):not(.swal2-loading) .swal2-styled:hover{background-image:linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1))}div:where(.swal2-container) div:where(.swal2-actions):not(.swal2-loading) .swal2-styled:active{background-image:linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2))}div:where(.swal2-container) div:where(.swal2-loader){display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:#2778c4 rgba(0,0,0,0) #2778c4 rgba(0,0,0,0)}div:where(.swal2-container) button:where(.swal2-styled){margin:.3125em;padding:.625em 1.1em;transition:box-shadow .1s;box-shadow:0 0 0 3px rgba(0,0,0,0);font-weight:500}div:where(.swal2-container) button:where(.swal2-styled):not([disabled]){cursor:pointer}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm){border:0;border-radius:.25em;background:initial;background-color:#7066e0;color:#fff;font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):focus-visible{box-shadow:0 0 0 3px rgba(112,102,224,.5)}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny){border:0;border-radius:.25em;background:initial;background-color:#dc3741;color:#fff;font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):focus-visible{box-shadow:0 0 0 3px rgba(220,55,65,.5)}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel){border:0;border-radius:.25em;background:initial;background-color:#6e7881;color:#fff;font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):focus-visible{box-shadow:0 0 0 3px rgba(110,120,129,.5)}div:where(.swal2-container) button:where(.swal2-styled).swal2-default-outline:focus-visible{box-shadow:0 0 0 3px rgba(100,150,200,.5)}div:where(.swal2-container) button:where(.swal2-styled):focus-visible{outline:none}div:where(.swal2-container) button:where(.swal2-styled)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-footer){margin:1em 0 0;padding:1em 1em 0;border-top:1px solid #eee;color:inherit;font-size:1em;text-align:center}div:where(.swal2-container) .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto !important;overflow:hidden;border-bottom-right-radius:5px;border-bottom-left-radius:5px}div:where(.swal2-container) div:where(.swal2-timer-progress-bar){width:100%;height:.25em;background:rgba(0,0,0,.2)}div:where(.swal2-container) img:where(.swal2-image){max-width:100%;margin:2em auto 1em}div:where(.swal2-container) button:where(.swal2-close){z-index:2;align-items:center;justify-content:center;width:1.2em;height:1.2em;margin-top:0;margin-right:0;margin-bottom:-1.2em;padding:0;overflow:hidden;transition:color .1s,box-shadow .1s;border:none;border-radius:5px;background:rgba(0,0,0,0);color:#ccc;font-family:monospace;font-size:2.5em;cursor:pointer;justify-self:end}div:where(.swal2-container) button:where(.swal2-close):hover{transform:none;background:rgba(0,0,0,0);color:#f27474}div:where(.swal2-container) button:where(.swal2-close):focus-visible{outline:none;box-shadow:inset 0 0 0 3px rgba(100,150,200,.5)}div:where(.swal2-container) button:where(.swal2-close)::-moz-focus-inner{border:0}div:where(.swal2-container) .swal2-html-container{z-index:1;justify-content:center;margin:0;padding:1em 1.6em .3em;overflow:auto;color:inherit;font-size:1.125em;font-weight:normal;line-height:normal;text-align:center;word-wrap:break-word;word-break:break-word}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea),div:where(.swal2-container) select:where(.swal2-select),div:where(.swal2-container) div:where(.swal2-radio),div:where(.swal2-container) label:where(.swal2-checkbox){margin:1em 2em 3px}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea){box-sizing:border-box;width:auto;transition:border-color .1s,box-shadow .1s;border:1px solid #d9d9d9;border-radius:.1875em;background:rgba(0,0,0,0);box-shadow:inset 0 1px 1px rgba(0,0,0,.06),0 0 0 3px rgba(0,0,0,0);color:inherit;font-size:1.125em}div:where(.swal2-container) input:where(.swal2-input).swal2-inputerror,div:where(.swal2-container) input:where(.swal2-file).swal2-inputerror,div:where(.swal2-container) textarea:where(.swal2-textarea).swal2-inputerror{border-color:#f27474 !important;box-shadow:0 0 2px #f27474 !important}div:where(.swal2-container) input:where(.swal2-input):focus,div:where(.swal2-container) input:where(.swal2-file):focus,div:where(.swal2-container) textarea:where(.swal2-textarea):focus{border:1px solid #b4dbed;outline:none;box-shadow:inset 0 1px 1px rgba(0,0,0,.06),0 0 0 3px rgba(100,150,200,.5)}div:where(.swal2-container) input:where(.swal2-input)::placeholder,div:where(.swal2-container) input:where(.swal2-file)::placeholder,div:where(.swal2-container) textarea:where(.swal2-textarea)::placeholder{color:#ccc}div:where(.swal2-container) .swal2-range{margin:1em 2em 3px;background:#fff}div:where(.swal2-container) .swal2-range input{width:80%}div:where(.swal2-container) .swal2-range output{width:20%;color:inherit;font-weight:600;text-align:center}div:where(.swal2-container) .swal2-range input,div:where(.swal2-container) .swal2-range output{height:2.625em;padding:0;font-size:1.125em;line-height:2.625em}div:where(.swal2-container) .swal2-input{height:2.625em;padding:0 .75em}div:where(.swal2-container) .swal2-file{width:75%;margin-right:auto;margin-left:auto;background:rgba(0,0,0,0);font-size:1.125em}div:where(.swal2-container) .swal2-textarea{height:6.75em;padding:.75em}div:where(.swal2-container) .swal2-select{min-width:50%;max-width:100%;padding:.375em .625em;background:rgba(0,0,0,0);color:inherit;font-size:1.125em}div:where(.swal2-container) .swal2-radio,div:where(.swal2-container) .swal2-checkbox{align-items:center;justify-content:center;background:#fff;color:inherit}div:where(.swal2-container) .swal2-radio label,div:where(.swal2-container) .swal2-checkbox label{margin:0 .6em;font-size:1.125em}div:where(.swal2-container) .swal2-radio input,div:where(.swal2-container) .swal2-checkbox input{flex-shrink:0;margin:0 .4em}div:where(.swal2-container) label:where(.swal2-input-label){display:flex;justify-content:center;margin:1em auto 0}div:where(.swal2-container) div:where(.swal2-validation-message){align-items:center;justify-content:center;margin:1em 0 0;padding:.625em;overflow:hidden;background:#f0f0f0;color:#666;font-size:1em;font-weight:300}div:where(.swal2-container) div:where(.swal2-validation-message)::before{content:\"!\";display:inline-block;width:1.5em;min-width:1.5em;height:1.5em;margin:0 .625em;border-radius:50%;background-color:#f27474;color:#fff;font-weight:600;line-height:1.5em;text-align:center}div:where(.swal2-container) .swal2-progress-steps{flex-wrap:wrap;align-items:center;max-width:100%;margin:1.25em auto;padding:0;background:rgba(0,0,0,0);font-weight:600}div:where(.swal2-container) .swal2-progress-steps li{display:inline-block;position:relative}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:#2778c4;color:#fff;line-height:2em;text-align:center}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:#2778c4}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step{background:#add8e6;color:#fff}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step-line{background:#add8e6}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:#2778c4}div:where(.swal2-icon){position:relative;box-sizing:content-box;justify-content:center;width:5em;height:5em;margin:2.5em auto .6em;border:0.25em solid rgba(0,0,0,0);border-radius:50%;border-color:#000;font-family:inherit;line-height:5em;cursor:default;user-select:none}div:where(.swal2-icon) .swal2-icon-content{display:flex;align-items:center;font-size:3.75em}div:where(.swal2-icon).swal2-error{border-color:#f27474;color:#f27474}div:where(.swal2-icon).swal2-error .swal2-x-mark{position:relative;flex-grow:1}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line]{display:block;position:absolute;top:2.3125em;width:2.9375em;height:.3125em;border-radius:.125em;background-color:#f27474}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=left]{left:1.0625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=right]{right:1em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-error.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-error.swal2-icon-show .swal2-x-mark{animation:swal2-animate-error-x-mark .5s}div:where(.swal2-icon).swal2-warning{border-color:#facea8;color:#f8bb86}div:where(.swal2-icon).swal2-warning.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-warning.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .5s}div:where(.swal2-icon).swal2-info{border-color:#9de0f6;color:#3fc3ee}div:where(.swal2-icon).swal2-info.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-info.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .8s}div:where(.swal2-icon).swal2-question{border-color:#c9dae1;color:#87adbd}div:where(.swal2-icon).swal2-question.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-question.swal2-icon-show .swal2-icon-content{animation:swal2-animate-question-mark .8s}div:where(.swal2-icon).swal2-success{border-color:#a5dc86;color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line]{position:absolute;width:3.75em;height:7.5em;border-radius:50%}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.4375em;left:-2.0635em;transform:rotate(-45deg);transform-origin:3.75em 3.75em;border-radius:7.5em 0 0 7.5em}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.6875em;left:1.875em;transform:rotate(-45deg);transform-origin:0 3.75em;border-radius:0 7.5em 7.5em 0}div:where(.swal2-icon).swal2-success .swal2-success-ring{position:absolute;z-index:2;top:-0.25em;left:-0.25em;box-sizing:content-box;width:100%;height:100%;border:.25em solid rgba(165,220,134,.3);border-radius:50%}div:where(.swal2-icon).swal2-success .swal2-success-fix{position:absolute;z-index:1;top:.5em;left:1.625em;width:.4375em;height:5.625em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line]{display:block;position:absolute;z-index:2;height:.3125em;border-radius:.125em;background-color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=tip]{top:2.875em;left:.8125em;width:1.5625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=long]{top:2.375em;right:.5em;width:2.9375em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-animate-success-line-tip .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-animate-success-line-long .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-circular-line-right{animation:swal2-rotate-success-circular-line 4.25s ease-in}[class^=swal2]{-webkit-tap-highlight-color:rgba(0,0,0,0)}.swal2-show{animation:swal2-show .3s}.swal2-hide{animation:swal2-hide .15s forwards}.swal2-noanimation{transition:none}.swal2-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.swal2-rtl .swal2-close{margin-right:initial;margin-left:0}.swal2-rtl .swal2-timer-progress-bar{right:0;left:auto}@keyframes swal2-toast-show{0%{transform:translateY(-0.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(0.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0deg)}}@keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-0.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}@keyframes swal2-show{0%{transform:scale(0.7)}45%{transform:scale(1.05)}80%{transform:scale(0.95)}100%{transform:scale(1)}}@keyframes swal2-hide{0%{transform:scale(1);opacity:1}100%{transform:scale(0.5);opacity:0}}@keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-0.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(0.4);opacity:0}50%{margin-top:1.625em;transform:scale(0.4);opacity:0}80%{margin-top:-0.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);opacity:1}}@keyframes swal2-rotate-loading{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes swal2-animate-question-mark{0%{transform:rotateY(-360deg)}100%{transform:rotateY(0)}}@keyframes swal2-animate-i-mark{0%{transform:rotateZ(45deg);opacity:0}25%{transform:rotateZ(-25deg);opacity:.4}50%{transform:rotateZ(15deg);opacity:.8}75%{transform:rotateZ(-5deg);opacity:1}100%{transform:rotateX(0);opacity:1}}body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown){overflow:hidden}body.swal2-height-auto{height:auto !important}body.swal2-no-backdrop .swal2-container{background-color:rgba(0,0,0,0) !important;pointer-events:none}body.swal2-no-backdrop .swal2-container .swal2-popup{pointer-events:all}body.swal2-no-backdrop .swal2-container .swal2-modal{box-shadow:0 0 10px rgba(0,0,0,.4)}@media print{body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown){overflow-y:scroll !important}body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown)>[aria-hidden=true]{display:none}body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) .swal2-container{position:static !important}}body.swal2-toast-shown .swal2-container{box-sizing:border-box;width:360px;max-width:100%;background-color:rgba(0,0,0,0);pointer-events:none}body.swal2-toast-shown .swal2-container.swal2-top{inset:0 auto auto 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-top-end,body.swal2-toast-shown .swal2-container.swal2-top-right{inset:0 0 auto auto}body.swal2-toast-shown .swal2-container.swal2-top-start,body.swal2-toast-shown .swal2-container.swal2-top-left{inset:0 auto auto 0}body.swal2-toast-shown .swal2-container.swal2-center-start,body.swal2-toast-shown .swal2-container.swal2-center-left{inset:50% auto auto 0;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-center{inset:50% auto auto 50%;transform:translate(-50%, -50%)}body.swal2-toast-shown .swal2-container.swal2-center-end,body.swal2-toast-shown .swal2-container.swal2-center-right{inset:50% 0 auto auto;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-start,body.swal2-toast-shown .swal2-container.swal2-bottom-left{inset:auto auto 0 0}body.swal2-toast-shown .swal2-container.swal2-bottom{inset:auto auto 0 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-end,body.swal2-toast-shown .swal2-container.swal2-bottom-right{inset:auto 0 0 auto}"); \ No newline at end of file diff --git a/public/scripts/themes/theme-switcher.js b/public/scripts/themes/theme-switcher.js new file mode 100644 index 00000000..dd30ff87 --- /dev/null +++ b/public/scripts/themes/theme-switcher.js @@ -0,0 +1,21 @@ +document.addEventListener("DOMContentLoaded", function () { + const themeStylesheet = document.getElementById("theme-stylesheet"); + + // Load saved theme from local storage + const savedTheme = localStorage.getItem("theme"); + if (savedTheme) { + const safeTheme = ((savedTheme != 'default') ? encodeURIComponent(savedTheme) : encodeURIComponent('..')); + themeStylesheet.href = `styles/themes/${safeTheme}/bootstrap-min.css`; + } + + // Initialize Select2 on all select elements with the 'select2' class + $(".select2").select2({ + theme: "bootstrap-5", + width: $(this).data("width") + ? $(this).data("width") + : $(this).hasClass("w-100") + ? "100%" + : "style", + placeholder: $(this).data("placeholder"), + }); +}); diff --git a/public/scripts/u2f-api-min.js b/public/scripts/u2f-api-min.js index 8526385e..e7ec9870 100644 --- a/public/scripts/u2f-api-min.js +++ b/public/scripts/u2f-api-min.js @@ -1 +1 @@ -"use strict";var u2f,js_api_version;window.u2f||((u2f=u2f||{}).EXTENSION_ID="kmendfapggjehodndflmmgagdbamhnfd",u2f.MessageTypes={U2F_REGISTER_REQUEST:"u2f_register_request",U2F_REGISTER_RESPONSE:"u2f_register_response",U2F_SIGN_REQUEST:"u2f_sign_request",U2F_SIGN_RESPONSE:"u2f_sign_response",U2F_GET_API_VERSION_REQUEST:"u2f_get_api_version_request",U2F_GET_API_VERSION_RESPONSE:"u2f_get_api_version_response"},u2f.ErrorCodes={OK:0,OTHER_ERROR:1,BAD_REQUEST:2,CONFIGURATION_UNSUPPORTED:3,DEVICE_INELIGIBLE:4,TIMEOUT:5},u2f.U2fRequest,u2f.U2fResponse,u2f.Error,u2f.Transport,u2f.Transports,u2f.SignRequest,u2f.SignResponse,u2f.RegisterRequest,u2f.RegisterResponse,u2f.RegisteredKey,u2f.GetJsApiVersionResponse,u2f.getMessagePort=function(e){var t;"undefined"!=typeof chrome&&chrome.runtime?(t={type:u2f.MessageTypes.U2F_SIGN_REQUEST,signRequests:[]},chrome.runtime.sendMessage(u2f.EXTENSION_ID,t,function(){chrome.runtime.lastError?u2f.getIframePort_(e):u2f.getChromeRuntimePort_(e)})):u2f.isAndroidChrome_()?u2f.getAuthenticatorPort_(e):u2f.isIosChrome_()?u2f.getIosPort_(e):u2f.getIframePort_(e)},u2f.isAndroidChrome_=function(){var e=navigator.userAgent;return-1!=e.indexOf("Chrome")&&-1!=e.indexOf("Android")},u2f.isIosChrome_=function(){var e,t=["iPhone","iPad","iPod"];for(e in t)if(navigator.platform==t[e])return!0;return!1},u2f.getChromeRuntimePort_=function(e){var t=chrome.runtime.connect(u2f.EXTENSION_ID,{includeTlsChannelId:!0});setTimeout(function(){e(new u2f.WrappedChromeRuntimePort_(t))},0)},u2f.getAuthenticatorPort_=function(e){setTimeout(function(){e(new u2f.WrappedAuthenticatorPort_)},0)},u2f.getIosPort_=function(e){setTimeout(function(){e(new u2f.WrappedIosPort_)},0)},u2f.WrappedChromeRuntimePort_=function(e){this.port_=e},u2f.formatSignRequest_=function(e,t,o,r,n){if(void 0===js_api_version||js_api_version<1.1){for(var s=[],u=0;u{"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()})(window,function(){return r=[function(e,t,r){function n(){}Object.defineProperty(t,"__esModule",{value:!0}),n.prototype.activate=function(e){this._terminal=e},n.prototype.dispose=function(){},n.prototype.fit=function(){var e,t=this.proposeDimensions();t&&this._terminal&&(e=this._terminal._core,this._terminal.rows===t.rows&&this._terminal.cols===t.cols||(e._renderService.clear(),this._terminal.resize(t.cols,t.rows)))},n.prototype.proposeDimensions=function(){var e,t,r,n;if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement)return e=this._terminal._core,n=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(n.getPropertyValue("height")),n=Math.max(0,parseInt(n.getPropertyValue("width"))),t=window.getComputedStyle(this._terminal.element),r=r-(parseInt(t.getPropertyValue("padding-top"))+parseInt(t.getPropertyValue("padding-bottom"))),n=n-(parseInt(t.getPropertyValue("padding-right"))+parseInt(t.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth,{cols:Math.max(2,Math.floor(n/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(r/e._renderService.dimensions.actualCellHeight))}},t.FitAddon=n}],n={},o.m=r,o.c=n,o.d=function(e,t,r){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(o.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)o.d(r,n,function(e){return t[e]}.bind(null,n));return r},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=0);function o(e){var t;return(n[e]||(t=n[e]={i:e,l:!1,exports:{}},r[e].call(t.exports,t,t.exports,o),t.l=!0,t)).exports}var r,n}) \ No newline at end of file diff --git a/public/scripts/xterm-min.js b/public/scripts/xterm-min.js index 93048612..0e8cf0b6 100644 --- a/public/scripts/xterm-min.js +++ b/public/scripts/xterm-min.js @@ -1 +1 @@ -!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i,s=t();for(i in s)("object"==typeof exports?exports:e)[i]=s[i]}}(self,function(){return(()=>{"use strict";var i={4567:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;const s=i(9042),r=i(6114),n=i(9924),o=i(3656),a=i(844),h=i(5596),l=i(9631);class c extends a.Disposable{constructor(e,t){super(),this._terminal=e,this._renderService=t,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityTreeRoot=document.createElement("div"),this._accessibilityTreeRoot.classList.add("xterm-accessibility"),this._accessibilityTreeRoot.tabIndex=0,this._rowContainer=document.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;ethis._onBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._onBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityTreeRoot.appendChild(this._rowContainer),this._renderRowsDebouncer=new n.TimeBasedDebouncer(this._renderRows.bind(this)),this._refreshRows(),this._liveRegion=document.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityTreeRoot.appendChild(this._liveRegion),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityTreeRoot),this.register(this._renderRowsDebouncer),this.register(this._terminal.onResize(e=>this._onResize(e.rows))),this.register(this._terminal.onRender(e=>this._refreshRows(e.start,e.end))),this.register(this._terminal.onScroll(()=>this._refreshRows())),this.register(this._terminal.onA11yChar(e=>this._onChar(e))),this.register(this._terminal.onLineFeed(()=>this._onChar("\n"))),this.register(this._terminal.onA11yTab(e=>this._onTab(e))),this.register(this._terminal.onKey(e=>this._onKey(e.key))),this.register(this._terminal.onBlur(()=>this._clearLiveRegion())),this.register(this._renderService.onDimensionsChange(()=>this._refreshRowsDimensions())),this._screenDprMonitor=new h.ScreenDprMonitor(window),this.register(this._screenDprMonitor),this._screenDprMonitor.setListener(()=>this._refreshRowsDimensions()),this.register((0,o.addDisposableDomListener)(window,"resize",()=>this._refreshRowsDimensions()))}dispose(){super.dispose(),(0,l.removeElementFromParent)(this._accessibilityTreeRoot),this._rowElements.length=0}_onBoundaryFocus(i,s){var r=i.target,e=this._rowElements[0===s?1:this._rowElements.length-2];if(r.getAttribute("aria-posinset")!==(0===s?"1":""+this._terminal.buffer.lines.length)&&i.relatedTarget===e){let e,t;if(0===s?(e=r,t=this._rowElements.pop(),this._rowContainer.removeChild(t)):(e=this._rowElements.shift(),t=r,this._rowContainer.removeChild(e)),e.removeEventListener("focus",this._topBoundaryFocusListener),t.removeEventListener("focus",this._bottomBoundaryFocusListener),0===s){const i=this._createAccessibilityTreeNode();this._rowElements.unshift(i),this._rowContainer.insertAdjacentElement("afterbegin",i)}else{const i=this._createAccessibilityTreeNode();this._rowElements.push(i),this._rowContainer.appendChild(i)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===s?-1:1),this._rowElements[0===s?1:this._rowElements.length-2].focus(),i.preventDefault(),i.stopImmediatePropagation()}}_onResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){var e=document.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_onTab(t){for(let e=0;e{this._accessibilityTreeRoot.appendChild(this._liveRegion)},0)}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0,r.isMac&&(0,l.removeElementFromParent)(this._liveRegion)}_onKey(e){this._clearLiveRegion(),this._charsToConsume.push(e)}_refreshRows(e,t){this._renderRowsDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(t,i){var s=this._terminal.buffer,r=s.lines.length.toString();for(let e=t;e<=i;e++){const t=s.translateBufferLineToString(s.ydisp+e,!0),i=(s.ydisp+e+1).toString(),n=this._rowElements[e];n&&(0===t.length?n.innerText=" ":n.textContent=t,n.setAttribute("aria-posinset",i),n.setAttribute("aria-setsize",r))}this._announceCharacters()}_refreshRowsDimensions(){if(this._renderService.dimensions.actualCellHeight){this._rowElements.length!==this._terminal.rows&&this._onResize(this._terminal.rows);for(let e=0;e{function s(e){return e.replace(/\r?\n/g,"\r")}function r(e,t){return t?"[200~"+e+"[201~":e}function n(e,t,i){e=r(e=s(e),i.decPrivateModes.bracketedPasteMode),i.triggerDataEvent(e,!0),t.value=""}function o(e,t,i){var i=i.getBoundingClientRect(),s=e.clientX-i.left-10,e=e.clientY-i.top-10;t.style.width="20px",t.style.height="20px",t.style.left=s+"px",t.style.top=e+"px",t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=s,t.bracketTextForPaste=r,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,i){e.stopPropagation(),e.clipboardData&&n(e.clipboardData.getData("text/plain"),t,i)},t.paste=n,t.moveTextAreaUnderMouseCursor=o,t.rightClickHandler=function(e,t,i,s,r){o(e,t,i),r&&s.rightClickSelect(e),t.value=s.selectionText,t.select()}},7239:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;const s=i(1505);t.ColorContrastCache=class{constructor(){this._color=new s.TwoKeyMap,this._css=new s.TwoKeyMap}setCss(e,t,i){this._css.set(e,t,i)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,i){this._color.set(e,t,i)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},5680:(e,s,t)=>{Object.defineProperty(s,"__esModule",{value:!0}),s.ColorManager=s.DEFAULT_ANSI_COLORS=void 0;const h=t(8055),i=t(7239),r=h.css.toColor("#ffffff"),n=h.css.toColor("#000000"),o=h.css.toColor("#ffffff"),a=h.css.toColor("#000000"),l={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};s.DEFAULT_ANSI_COLORS=Object.freeze((()=>{var t=[h.css.toColor("#2e3436"),h.css.toColor("#cc0000"),h.css.toColor("#4e9a06"),h.css.toColor("#c4a000"),h.css.toColor("#3465a4"),h.css.toColor("#75507b"),h.css.toColor("#06989a"),h.css.toColor("#d3d7cf"),h.css.toColor("#555753"),h.css.toColor("#ef2929"),h.css.toColor("#8ae234"),h.css.toColor("#fce94f"),h.css.toColor("#729fcf"),h.css.toColor("#ad7fa8"),h.css.toColor("#34e2e2"),h.css.toColor("#eeeeec")],i=[0,95,135,175,215,255];for(let e=0;e<216;e++){var s=i[e/36%6|0],r=i[e/6%6|0],n=i[e%6];t.push({css:h.channels.toCss(s,r,n),rgba:h.channels.toRgba(s,r,n)})}for(let e=0;e<24;e++){var o=8+10*e;t.push({css:h.channels.toCss(o,o,o),rgba:h.channels.toRgba(o,o,o)})}return t})()),s.ColorManager=class{constructor(e,t){this.allowTransparency=t;t=e.createElement("canvas"),t.width=1,t.height=1,e=t.getContext("2d");if(!e)throw new Error("Could not get rendering context");this._ctx=e,this._ctx.globalCompositeOperation="copy",this._litmusColor=this._ctx.createLinearGradient(0,0,1,1),this._contrastCache=new i.ColorContrastCache,this.colors={foreground:r,background:n,cursor:o,cursorAccent:a,selectionForeground:void 0,selectionBackgroundTransparent:l,selectionBackgroundOpaque:h.color.blend(n,l),selectionInactiveBackgroundTransparent:l,selectionInactiveBackgroundOpaque:h.color.blend(n,l),ansi:s.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache},this._updateRestoreColors()}onOptionsChange(e,t){switch(e){case"minimumContrastRatio":this._contrastCache.clear();break;case"allowTransparency":this.allowTransparency=t}}setTheme(t={}){this.colors.foreground=this._parseColor(t.foreground,r),this.colors.background=this._parseColor(t.background,n),this.colors.cursor=this._parseColor(t.cursor,o,!0),this.colors.cursorAccent=this._parseColor(t.cursorAccent,a,!0),this.colors.selectionBackgroundTransparent=this._parseColor(t.selectionBackground,l,!0),this.colors.selectionBackgroundOpaque=h.color.blend(this.colors.background,this.colors.selectionBackgroundTransparent),this.colors.selectionInactiveBackgroundTransparent=this._parseColor(t.selectionInactiveBackground,this.colors.selectionBackgroundTransparent,!0),this.colors.selectionInactiveBackgroundOpaque=h.color.blend(this.colors.background,this.colors.selectionInactiveBackgroundTransparent);const i={css:"",rgba:0};if(this.colors.selectionForeground=t.selectionForeground?this._parseColor(t.selectionForeground,i):void 0,this.colors.selectionForeground===i&&(this.colors.selectionForeground=void 0),h.color.isOpaque(this.colors.selectionBackgroundTransparent)){const t=.3;this.colors.selectionBackgroundTransparent=h.color.opacity(this.colors.selectionBackgroundTransparent,.3)}if(h.color.isOpaque(this.colors.selectionInactiveBackgroundTransparent)){const t=.3;this.colors.selectionInactiveBackgroundTransparent=h.color.opacity(this.colors.selectionInactiveBackgroundTransparent,.3)}if(this.colors.ansi=s.DEFAULT_ANSI_COLORS.slice(),this.colors.ansi[0]=this._parseColor(t.black,s.DEFAULT_ANSI_COLORS[0]),this.colors.ansi[1]=this._parseColor(t.red,s.DEFAULT_ANSI_COLORS[1]),this.colors.ansi[2]=this._parseColor(t.green,s.DEFAULT_ANSI_COLORS[2]),this.colors.ansi[3]=this._parseColor(t.yellow,s.DEFAULT_ANSI_COLORS[3]),this.colors.ansi[4]=this._parseColor(t.blue,s.DEFAULT_ANSI_COLORS[4]),this.colors.ansi[5]=this._parseColor(t.magenta,s.DEFAULT_ANSI_COLORS[5]),this.colors.ansi[6]=this._parseColor(t.cyan,s.DEFAULT_ANSI_COLORS[6]),this.colors.ansi[7]=this._parseColor(t.white,s.DEFAULT_ANSI_COLORS[7]),this.colors.ansi[8]=this._parseColor(t.brightBlack,s.DEFAULT_ANSI_COLORS[8]),this.colors.ansi[9]=this._parseColor(t.brightRed,s.DEFAULT_ANSI_COLORS[9]),this.colors.ansi[10]=this._parseColor(t.brightGreen,s.DEFAULT_ANSI_COLORS[10]),this.colors.ansi[11]=this._parseColor(t.brightYellow,s.DEFAULT_ANSI_COLORS[11]),this.colors.ansi[12]=this._parseColor(t.brightBlue,s.DEFAULT_ANSI_COLORS[12]),this.colors.ansi[13]=this._parseColor(t.brightMagenta,s.DEFAULT_ANSI_COLORS[13]),this.colors.ansi[14]=this._parseColor(t.brightCyan,s.DEFAULT_ANSI_COLORS[14]),this.colors.ansi[15]=this._parseColor(t.brightWhite,s.DEFAULT_ANSI_COLORS[15]),t.extendedAnsi){const i=Math.min(this.colors.ansi.length-16,t.extendedAnsi.length);for(let e=0;eNumber(e)),a=Math.round(255*o);return{rgba:h.channels.toRgba(s,r,n,a),css:e}}}}},9631:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.removeElementFromParent=void 0,t.removeElementFromParent=function(...e){var t;for(const i of e)null!=(t=null==i?void 0:i.parentElement)&&t.removeChild(i)}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,i,s){e.addEventListener(t,i,s);let r=!1;return{dispose:()=>{r||(r=!0,e.removeEventListener(t,i,s))}}}},6465:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3{var e=this._linkProviders.indexOf(t);-1!==e&&this._linkProviders.splice(e,1)}}}attachToDom(e,t,i){this._element=e,this._mouseService=t,this._renderService=i,this.register((0,h.addDisposableDomListener)(this._element,"mouseleave",()=>{this._isMouseOut=!0,this._clearCurrentLink()})),this.register((0,h.addDisposableDomListener)(this._element,"mousemove",this._onMouseMove.bind(this))),this.register((0,h.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,h.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_onMouseMove(e){if(this._lastMouseEvent=e,this._element&&this._mouseService){const i=this._positionFromMouseEvent(e,this._element,this._mouseService);if(i){this._isMouseOut=!1;var t=e.composedPath();for(let e=0;e{null!=e&&e.forEach(e=>{e.link.dispose&&e.link.dispose()})}),this._activeProviderReplies=new Map,this._activeLine=i.y);let r=!1;for(const[s,n]of this._linkProviders.entries())e?null!=(t=this._activeProviderReplies)&&t.get(s)&&(r=this._checkLinkProviderResult(s,i,r)):n.provideLinks(i.y,e=>{var t;this._isMouseOut||(e=null==e?void 0:e.map(e=>({link:e})),null!=(t=this._activeProviderReplies)&&t.set(s,e),r=this._checkLinkProviderResult(s,i,r),(null==(t=this._activeProviderReplies)?void 0:t.size)===this._linkProviders.length&&this._removeIntersectingLinks(i.y,this._activeProviderReplies))})}_removeIntersectingLinks(i,t){var s=new Set;for(let e=0;ei?this._bufferService.cols:n.link.range.end.x;for(let e=o;e<=a;e++){if(s.has(e)){r.splice(t--,1);break}s.add(e)}}}}_checkLinkProviderResult(i,s,r){var n;if(this._activeProviderReplies){const o=this._activeProviderReplies.get(i);let t=!1;for(let e=0;ethis._linkAtPosition(e.link,s));i&&(r=!0,this._handleNewLink(i))}if(this._activeProviderReplies.size===this._linkProviders.length&&!r)for(let e=0;ethis._linkAtPosition(e.link,s));if(o){r=!0,this._handleNewLink(o);break}}}return r}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){var t;this._element&&this._mouseService&&this._currentLink&&(t=this._positionFromMouseEvent(e,this._element,this._mouseService))&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._element&&this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),(this._currentLink=void 0,a.disposeArray)(this._linkCacheDisposables))}_handleNewLink(i){var e;this._element&&this._lastMouseEvent&&this._mouseService&&(e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService))&&this._linkAtPosition(i.link,e)&&(this._currentLink=i,this._currentLink.state={decorations:{underline:void 0===i.link.decorations||i.link.decorations.underline,pointerCursor:void 0===i.link.decorations||i.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,i.link,this._lastMouseEvent),i.link.decorations={},Object.defineProperties(i.link.decorations,{pointerCursor:{get:()=>{var e;return null==(e=null==(e=this._currentLink)?void 0:e.state)?void 0:e.decorations.pointerCursor},set:e=>{var t;null!=(t=this._currentLink)&&t.state&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered)&&(null!=(t=this._element)&&t.classList.toggle("xterm-cursor-pointer",e))}},underline:{get:()=>{var e;return null==(e=null==(e=this._currentLink)?void 0:e.state)?void 0:e.decorations.underline},set:e=>{var t;null!=(t=this._currentLink)&&t.state&&(null==(t=null==(t=this._currentLink)?void 0:t.state)?void 0:t.decorations.underline)!==e&&(this._currentLink.state.decorations.underline=e,this._currentLink.state.isHovered)&&this._fireUnderlineEvent(i.link,e)}}}),this._renderService)&&this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange(e=>{var t=0===e.start?0:e.start+1+this._bufferService.buffer.ydisp;this._clearCurrentLink(t,e.end+1+this._bufferService.buffer.ydisp)}))}_linkHover(e,t,i){var s;null!=(s=this._currentLink)&&s.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor)&&e.classList.add("xterm-cursor-pointer"),t.hover&&t.hover(i,t.text)}_fireUnderlineEvent(e,t){var e=e.range,i=this._bufferService.buffer.ydisp,e=this._createLinkUnderlineEvent(e.start.x-1,e.start.y-i-1,e.end.x,e.end.y-i-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(e)}_linkLeave(e,t,i){var s;null!=(s=this._currentLink)&&s.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor)&&e.classList.remove("xterm-cursor-pointer"),t.leave&&t.leave(i,t.text)}_linkAtPosition(e,t){var i=e.range.start.y===e.range.end.y,s=e.range.start.yt.y;return(i&&e.range.start.x<=t.x&&e.range.end.x>=t.x||s&&e.range.end.x>=t.x||r&&e.range.start.x<=t.x||s&&r)&&e.range.start.y<=t.y&&e.range.end.y>=t.y}_positionFromMouseEvent(e,t,i){i=i.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(i)return{x:i[0],y:i[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,i,s,r){return{x1:e,y1:t,x2:i,y2:s,cols:this._bufferService.cols,fg:r}}},i=s([r(0,n.IBufferService)],i);t.Linkifier2=i},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},2962:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3{if(h)return h.activate(e,t,n);e=t;if(confirm(`Do you want to navigate to ${e}?`)){const i=window.open();if(i){try{i.opener=null}catch(i){}i.location.href=e}else console.warn("Opening link blocked as opener could not be cleared")}},hover:(e,t)=>{var i;return null==(i=null==h?void 0:h.hover)?void 0:i.call(h,e,t,n)},leave:(e,t)=>{var i;return null==(i=null==h?void 0:h.leave)?void 0:i.call(h,e,t,n)}})}s=!1,t=l.hasExtendedAttrs()&&l.extended.urlId?(i=e,l.extended.urlId):i=-1}}e(a)}else e(void 0)}};i=s([r(0,n.IBufferService),r(1,n.IOptionsService),r(2,n.IOscLinkService)],i),t.OscLinkProvider=i},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._parentWindow=e,this._renderCallback=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&(this._parentWindow.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||(this._animationFrame=this._parentWindow.requestAnimationFrame(()=>this._innerRefresh())),this._animationFrame}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=this._parentWindow.requestAnimationFrame(()=>this._innerRefresh()))}_innerRefresh(){var e,t;(this._animationFrame=void 0)!==this._rowStart&&void 0!==this._rowEnd&&void 0!==this._rowCount&&(e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1),this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(const e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},5596:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ScreenDprMonitor=void 0;class s extends i(844).Disposable{constructor(e){super(),this._parentWindow=e,this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio}setListener(e){this._listener&&this.clearListener(),this._listener=e,this._outerListener=()=>{this._listener&&(this._listener(this._parentWindow.devicePixelRatio,this._currentDevicePixelRatio),this._updateDpr())},this._updateDpr()}dispose(){super.dispose(),this.clearListener()}_updateDpr(){var e;this._outerListener&&(null!=(e=this._resolutionMediaMatchList)&&e.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._listener&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._listener=void 0,this._outerListener=void 0)}}t.ScreenDprMonitor=s},3236:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;const s=i(2950),r=i(1680),n=i(3614),o=i(2584),a=i(5435),h=i(9312),l=i(6114),c=i(3656),_=i(9042),d=i(4567),u=i(1296),f=i(7399),v=i(8460),g=i(8437),p=i(5680),S=i(3230),m=i(4725),C=i(428),b=i(8934),y=i(6465),w=i(5114),E=i(8969),L=i(8055),R=i(4269),k=i(5941),D=i(3107),A=i(5744),x=i(9074),B=i(2585),T=i(2962),M="undefined"!=typeof window?window.document:null;class O extends E.CoreTerminal{constructor(e={}){super(e),this.browser=l,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._onCursorMove=new v.EventEmitter,this._onKey=new v.EventEmitter,this._onRender=new v.EventEmitter,this._onSelectionChange=new v.EventEmitter,this._onTitleChange=new v.EventEmitter,this._onBell=new v.EventEmitter,this._onFocus=new v.EventEmitter,this._onBlur=new v.EventEmitter,this._onA11yCharEmitter=new v.EventEmitter,this._onA11yTabEmitter=new v.EventEmitter,this._setup(),this.linkifier2=this.register(this._instantiationService.createInstance(y.Linkifier2)),this.linkifier2.registerLinkProvider(this._instantiationService.createInstance(T.OscLinkProvider)),this._decorationService=this._instantiationService.createInstance(x.DecorationService),this._instantiationService.setService(B.IDecorationService,this._decorationService),this.register(this._inputHandler.onRequestBell(()=>this._onBell.fire())),this.register(this._inputHandler.onRequestRefreshRows((e,t)=>this.refresh(e,t))),this.register(this._inputHandler.onRequestSendFocus(()=>this._reportFocus())),this.register(this._inputHandler.onRequestReset(()=>this.reset())),this.register(this._inputHandler.onRequestWindowsOptionsReport(e=>this._reportWindowsOptions(e))),this.register(this._inputHandler.onColor(e=>this._handleColorEvent(e))),this.register((0,v.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,v.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,v.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,v.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize(e=>this._afterResize(e.cols,e.rows)))}get onCursorMove(){return this._onCursorMove.event}get onKey(){return this._onKey.event}get onRender(){return this._onRender.event}get onSelectionChange(){return this._onSelectionChange.event}get onTitleChange(){return this._onTitleChange.event}get onBell(){return this._onBell.event}get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}_handleColorEvent(e){var i;if(this._colorManager){for(const i of e){let e,t="";switch(i.index){case 256:e="foreground",t="10";break;case 257:e="background",t="11";break;case 258:e="cursor",t="12";break;default:e="ansi",t="4;"+i.index}switch(i.type){case 0:var s=L.color.toColorRGB("ansi"===e?this._colorManager.colors.ansi[i.index]:this._colorManager.colors[e]);this.coreService.triggerDataEvent(`${o.C0.ESC}]${t};`+(0,k.toRgbString)(s)+o.C1_ESCAPED.ST);break;case 1:"ansi"===e?this._colorManager.colors.ansi[i.index]=L.rgba.toColor(...i.color):this._colorManager.colors[e]=L.rgba.toColor(...i.color);break;case 2:this._colorManager.restoreColor(i.index)}}null!=(i=this._renderService)&&i.setColors(this._colorManager.colors),null!=(e=this.viewport)&&e.onThemeChange(this._colorManager.colors)}}dispose(){var e;this._isDisposed||(super.dispose(),null!=(e=this._renderService)&&e.dispose(),this._customKeyEventHandler=void 0,this.write=()=>{},null==(e=null==(e=this.element)?void 0:e.parentNode))||e.removeChild(this.element)}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_updateOptions(e){var t;switch(super._updateOptions(e),e){case"fontFamily":case"fontSize":null!=(t=this._renderService)&&t.clear(),null!=(t=this._charSizeService)&&t.measure();break;case"cursorBlink":case"cursorStyle":this.refresh(this.buffer.y,this.buffer.y);break;case"customGlyphs":case"drawBoldTextInBrightColors":case"letterSpacing":case"lineHeight":case"fontWeight":case"fontWeightBold":case"minimumContrastRatio":this._renderService&&(this._renderService.clear(),this._renderService.onResize(this.cols,this.rows),this.refresh(0,this.rows-1));break;case"scrollback":null!=(t=this.viewport)&&t.syncScrollArea();break;case"screenReaderMode":this.optionsService.rawOptions.screenReaderMode?!this._accessibilityManager&&this._renderService&&(this._accessibilityManager=new d.AccessibilityManager(this,this._renderService)):(null!=(t=this._accessibilityManager)&&t.dispose(),this._accessibilityManager=void 0);break;case"tabStopWidth":this.buffers.setupTabStops();break;case"theme":this._setTheme(this.optionsService.rawOptions.theme)}}_onTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(o.C0.ESC+"[I"),this.updateCursorStyle(e),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()}blur(){var e;return null==(e=this.textarea)?void 0:e.blur()}_onTextAreaBlur(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(o.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()}_syncTextArea(){var e,t,i,s;this.textarea&&this.buffer.isCursorInViewport&&!this._compositionHelper.isComposing&&this._renderService&&(t=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(t))&&(s=Math.min(this.buffer.x,this.cols-1),e=this._renderService.dimensions.actualCellHeight,t=t.getWidth(s),t=this._renderService.dimensions.actualCellWidth*t,i=this.buffer.y*this._renderService.dimensions.actualCellHeight,s=s*this._renderService.dimensions.actualCellWidth,this.textarea.style.left=s+"px",this.textarea.style.top=i+"px",this.textarea.style.width=t+"px",this.textarea.style.height=e+"px",this.textarea.style.lineHeight=e+"px",this.textarea.style.zIndex="-5")}_initGlobal(){this._bindKeys(),this.register((0,c.addDisposableDomListener)(this.element,"copy",e=>{this.hasSelection()&&(0,n.copyHandler)(e,this._selectionService)}));var e=e=>(0,n.handlePasteEvent)(e,this.textarea,this.coreService);this.register((0,c.addDisposableDomListener)(this.textarea,"paste",e)),this.register((0,c.addDisposableDomListener)(this.element,"paste",e)),l.isFirefox?this.register((0,c.addDisposableDomListener)(this.element,"mousedown",e=>{2===e.button&&(0,n.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)})):this.register((0,c.addDisposableDomListener)(this.element,"contextmenu",e=>{(0,n.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)})),l.isLinux&&this.register((0,c.addDisposableDomListener)(this.element,"auxclick",e=>{1===e.button&&(0,n.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)}))}_bindKeys(){this.register((0,c.addDisposableDomListener)(this.textarea,"keyup",e=>this._keyUp(e),!0)),this.register((0,c.addDisposableDomListener)(this.textarea,"keydown",e=>this._keyDown(e),!0)),this.register((0,c.addDisposableDomListener)(this.textarea,"keypress",e=>this._keyPress(e),!0)),this.register((0,c.addDisposableDomListener)(this.textarea,"compositionstart",()=>this._compositionHelper.compositionstart())),this.register((0,c.addDisposableDomListener)(this.textarea,"compositionupdate",e=>this._compositionHelper.compositionupdate(e))),this.register((0,c.addDisposableDomListener)(this.textarea,"compositionend",()=>this._compositionHelper.compositionend())),this.register((0,c.addDisposableDomListener)(this.textarea,"input",e=>this._inputEvent(e),!0)),this.register(this.onRender(()=>this._compositionHelper.updateCompositionElements()))}open(e){if(!e)throw new Error("Terminal requires a parent element.");e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this._document=e.ownerDocument,this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),this.element.setAttribute("tabindex","0"),e.appendChild(this.element);var e=M.createDocumentFragment(),t=(this._viewportElement=M.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),e.appendChild(this._viewportElement),this._viewportScrollArea=M.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=M.createElement("div"),this.screenElement.classList.add("xterm-screen"),this._helperContainer=M.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),e.appendChild(this.screenElement),this.textarea=M.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",_.promptLabel),this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this.register((0,c.addDisposableDomListener)(this.textarea,"focus",e=>this._onTextAreaFocus(e))),this.register((0,c.addDisposableDomListener)(this.textarea,"blur",()=>this._onTextAreaBlur())),this._helperContainer.appendChild(this.textarea),this._coreBrowserService=this._instantiationService.createInstance(w.CoreBrowserService,this.textarea,null!=(t=this._document.defaultView)?t:window),this._instantiationService.setService(m.ICoreBrowserService,this._coreBrowserService),this._charSizeService=this._instantiationService.createInstance(C.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(m.ICharSizeService,this._charSizeService),this._theme=this.options.theme||this._theme,this._colorManager=new p.ColorManager(M,this.options.allowTransparency),this.register(this.optionsService.onOptionChange(e=>this._colorManager.onOptionsChange(e,this.optionsService.rawOptions[e]))),this._colorManager.setTheme(this._theme),this._characterJoinerService=this._instantiationService.createInstance(R.CharacterJoinerService),this._instantiationService.setService(m.ICharacterJoinerService,this._characterJoinerService),this._createRenderer());this._renderService=this.register(this._instantiationService.createInstance(S.RenderService,t,this.rows,this.screenElement)),this._instantiationService.setService(m.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange(e=>this._onRender.fire(e))),this.onResize(e=>this._renderService.resize(e.cols,e.rows)),this._compositionView=M.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(s.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this.element.appendChild(e),this._mouseService=this._instantiationService.createInstance(b.MouseService),this._instantiationService.setService(m.IMouseService,this._mouseService),this.viewport=this._instantiationService.createInstance(r.Viewport,e=>this.scrollLines(e,!0,1),this._viewportElement,this._viewportScrollArea,this.element),this.viewport.onThemeChange(this._colorManager.colors),this.register(this._inputHandler.onRequestSyncScrollBar(()=>this.viewport.syncScrollArea())),this.register(this.viewport),this.register(this.onCursorMove(()=>{this._renderService.onCursorMove(),this._syncTextArea()})),this.register(this.onResize(()=>this._renderService.onResize(this.cols,this.rows))),this.register(this.onBlur(()=>this._renderService.onBlur())),this.register(this.onFocus(()=>this._renderService.onFocus())),this.register(this._renderService.onDimensionsChange(()=>this.viewport.syncScrollArea())),this._selectionService=this.register(this._instantiationService.createInstance(h.SelectionService,this.element,this.screenElement,this.linkifier2)),this._instantiationService.setService(m.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines(e=>this.scrollLines(e.amount,e.suppressScrollEvent))),this.register(this._selectionService.onSelectionChange(()=>this._onSelectionChange.fire())),this.register(this._selectionService.onRequestRedraw(e=>this._renderService.onSelectionChanged(e.start,e.end,e.columnSelectMode))),this.register(this._selectionService.onLinuxMouseSelection(e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()})),this.register(this._onScroll.event(e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()})),this.register((0,c.addDisposableDomListener)(this._viewportElement,"scroll",()=>this._selectionService.refresh())),this.linkifier2.attachToDom(this.screenElement,this._mouseService,this._renderService),this.register(this._instantiationService.createInstance(D.BufferDecorationRenderer,this.screenElement)),this.register((0,c.addDisposableDomListener)(this.element,"mousedown",e=>this._selectionService.onMouseDown(e))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager=new d.AccessibilityManager(this,this._renderService)),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(A.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onOptionChange(()=>{!this._overviewRulerRenderer&&this.options.overviewRulerWidth&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(A.OverviewRulerRenderer,this._viewportElement,this.screenElement)))}),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(u.DomRenderer,this._colorManager.colors,this.element,this.screenElement,this._viewportElement,this.linkifier2)}_setTheme(e){var t;this._theme=e,null!=(t=this._colorManager)&&t.setTheme(e),null!=(t=this._renderService)&&t.setColors(this._colorManager.colors),null!=(e=this.viewport)&&e.onThemeChange(this._colorManager.colors)}bindMouse(){const r=this,t=this.element;function i(i){var s=r._mouseService.getMouseReportCoords(i,r.screenElement);if(s){let e,t;switch(i.overrideType||i.type){case"mousemove":t=32,void 0===i.buttons?(e=3,void 0!==i.button&&(e=i.button<3?i.button:3)):e=1&i.buttons?0:4&i.buttons?1:2&i.buttons?2:3;break;case"mouseup":t=0,e=i.button<3?i.button:3;break;case"mousedown":t=1,e=i.button<3?i.button:3;break;case"wheel":if(0===r.viewport.getLinesScrolled(i))return;t=i.deltaY<0?0:1,e=4;break;default:return}void 0===t||void 0===e||4(i(e),e.buttons||(this._document.removeEventListener("mouseup",n.mouseup),n.mousedrag&&this._document.removeEventListener("mousemove",n.mousedrag)),this.cancel(e)),wheel:e=>(i(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&i(e)},mousemove:e=>{e.buttons||i(e)}};this.register(this.coreMouseService.onProtocolChange(e=>{e?("debug"===this.optionsService.rawOptions.logLevel&&this._logService.debug("Binding to mouse events:",this.coreMouseService.explainEvents(e)),this.element.classList.add("enable-mouse-events"),this._selectionService.disable()):(this._logService.debug("Unbinding from mouse events."),this.element.classList.remove("enable-mouse-events"),this._selectionService.enable()),8&e?n.mousemove||(t.addEventListener("mousemove",s.mousemove),n.mousemove=s.mousemove):(t.removeEventListener("mousemove",n.mousemove),n.mousemove=null),16&e?n.wheel||(t.addEventListener("wheel",s.wheel,{passive:!1}),n.wheel=s.wheel):(t.removeEventListener("wheel",n.wheel),n.wheel=null),2&e?n.mouseup||(n.mouseup=s.mouseup):(this._document.removeEventListener("mouseup",n.mouseup),n.mouseup=null),4&e?n.mousedrag||(n.mousedrag=s.mousedrag):(this._document.removeEventListener("mousemove",n.mousedrag),n.mousedrag=null)})),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,c.addDisposableDomListener)(t,"mousedown",e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return i(e),n.mouseup&&this._document.addEventListener("mouseup",n.mouseup),n.mousedrag&&this._document.addEventListener("mousemove",n.mousedrag),this.cancel(e)})),this.register((0,c.addDisposableDomListener)(t,"wheel",e=>{if(!n.wheel){if(this.buffer.hasScrollback)return this.viewport.onWheel(e)?this.cancel(e):void 0;{var i=this.viewport.getLinesScrolled(e);if(0===i)return;var s=o.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(e.deltaY<0?"A":"B");let t="";for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.onTouchStart(e),this.cancel(e)},{passive:!0})),this.register((0,c.addDisposableDomListener)(t,"touchmove",e=>this.coreMouseService.areMouseEventsActive||this.viewport.onTouchMove(e)?void 0:this.cancel(e),{passive:!1}))}refresh(e,t){var i;null!=(i=this._renderService)&&i.refreshRows(e,t)}updateCursorStyle(e){var t;null!=(t=this._selectionService)&&t.shouldColumnSelect(e)?this.element.classList.add("column-select"):this.element.classList.remove("column-select")}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,i=0){super.scrollLines(e,t,i),this.refresh(0,this.rows-1)}paste(e){(0,n.paste)(e,this.textarea,this.coreService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}registerLinkProvider(e){return this.linkifier2.registerLinkProvider(e)}registerCharacterJoiner(e){if(this._characterJoinerService)return e=this._characterJoinerService.register(e),this.refresh(0,this.rows-1),e;throw new Error("Terminal must be opened first")}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}addMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,i){this._selectionService.setSelection(e,t,i)}getSelection(){return this._selectionService?this._selectionService.selectionText:""}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){var e;null!=(e=this._selectionService)&&e.clearSelection()}selectAll(){var e;null!=(e=this._selectionService)&&e.selectAll()}selectLines(e,t){var i;null!=(i=this._selectionService)&&i.selectLines(e,t)}_keyDown(e){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;const t=this.browser.isMac&&this.options.macOptionIsMeta&&e.altKey;if(!t&&!this._compositionHelper.keydown(e))return this.buffer.ybase!==this.buffer.ydisp&&this._bufferService.scrollToBottom(),!1;t||"Dead"!==e.key&&"AltGraph"!==e.key||(this._unprocessedDeadKey=!0);var i=(0,f.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),3!==i.type&&2!==i.type)return 1===i.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(i.cancel&&this.cancel(e,!0),!i.key)||!!(e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&1===e.key.length&&65<=e.key.charCodeAt(0)&&e.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?!(this._unprocessedDeadKey=!1):(i.key!==o.C0.ETX&&i.key!==o.C0.CR||(this.textarea.value=""),this._onKey.fire({key:i.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(i.key,!0),this.optionsService.rawOptions.screenReaderMode?void(this._keyDownHandled=!0):this.cancel(e,!0)));{const t=this.rows-1;return this.scrollLines(2===i.type?-t:t),this.cancel(e,!0)}}_isThirdLevelShift(e,t){e=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?e:e&&(!t.keyCode||47{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;i=Date.now();if(i-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=i,this._innerRefresh();else if(!this._additionalRefreshRequested){const e=i-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout(()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0},t)}}_innerRefresh(){var e,t;void 0!==this._rowStart&&void 0!==this._rowEnd&&void 0!==this._rowCount&&(e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1),this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t))}}},1680:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._activeBuffer=e.activeBuffer)),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange(e=>this._renderDimensions=e)),setTimeout(()=>this.syncScrollArea(),0)}onThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}_refresh(e){e?(this._innerRefresh(),null!==this._refreshAnimationFrame&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame)):null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame(()=>this._innerRefresh()))}_innerRefresh(){if(0this._smoothScroll()):this._clearSmoothScrollState())}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){var i=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||0this._queueRefresh())),this.register(this._renderService.onDimensionsChange(()=>{this._dimensionsChanged=!0,this._queueRefresh()})),this.register((0,n.addDisposableDomListener)(window,"resize",()=>this._queueRefresh())),this.register(this._bufferService.buffers.onBufferActivate(()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt})),this.register(this._decorationService.onDecorationRegistered(()=>this._queueRefresh())),this.register(this._decorationService.onDecorationRemoved(e=>this._removeDecoration(e)))}dispose(){this._container.remove(),this._decorationElements.clear(),super.dispose()}_queueRefresh(){void 0===this._animationFrame&&(this._animationFrame=this._renderService.addRefreshCallback(()=>{this.refreshDecorations(),this._animationFrame=void 0}))}refreshDecorations(){for(const e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){var t=document.createElement("div"),i=(t.classList.add("xterm-decoration"),t.style.width=Math.round((e.options.width||1)*this._renderService.dimensions.actualCellWidth)+"px",t.style.height=(e.options.height||1)*this._renderService.dimensions.actualCellHeight+"px",t.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.actualCellHeight+"px",t.style.lineHeight=this._renderService.dimensions.actualCellHeight+"px",null!=(i=e.options.x)?i:0);return i&&i>this._bufferService.cols&&(t.style.display="none"),this._refreshXPosition(e,t),t}_refreshStyle(t){var i=t.marker.line-this._bufferService.buffers.active.ydisp;if(i<0||i>=this._bufferService.rows)t.element&&(t.element.style.display="none",t.onRenderEmitter.fire(t.element));else{let e=this._decorationElements.get(t);e||(t.onDispose(()=>this._removeDecoration(t)),e=this._createElement(t),t.element=e,this._decorationElements.set(t,e),this._container.appendChild(e)),e.style.top=i*this._renderService.dimensions.actualCellHeight+"px",e.style.display=this._altBufferIsActive?"none":"block",t.onRenderEmitter.fire(e)}}_refreshXPosition(e,t=e.element){var i;t&&(i=null!=(i=e.options.x)?i:0,"right"===(e.options.anchor||"left")?t.style.right=i?i*this._renderService.dimensions.actualCellWidth+"px":"":t.style.left=i?i*this._renderService.dimensions.actualCellWidth+"px":"")}_removeDecoration(e){var t;null!=(t=this._decorationElements.get(e))&&t.remove(),this._decorationElements.delete(e)}},i=s([r(1,h.IBufferService),r(2,h.IDecorationService),r(3,o.IRenderService)],i);t.BufferDecorationRenderer=i},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(const t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,i){return t>=e.startBufferLine-this._linePadding[i||"full"]&&t<=e.endBufferLine+this._linePadding[i||"full"]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._queueRefresh(void 0,!0))),this.register(this._decorationService.onDecorationRemoved(()=>this._queueRefresh(void 0,!0)))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange(()=>this._queueRefresh())),this.register(this._bufferService.buffers.onBufferActivate(()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?"none":"block"})),this.register(this._bufferService.onScroll(()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())}))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender(()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)})),this.register(this._optionsService.onOptionChange(e=>{"overviewRulerWidth"===e&&this._queueRefresh(!0)})),this.register((0,n.addDisposableDomListener)(this._coreBrowseService.window,"resize",()=>{this._queueRefresh(!0)})),this._queueRefresh(!0)}dispose(){var e;null!=(e=this._canvas)&&e.remove(),super.dispose()}_refreshDrawConstants(){var e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);_.full=this._canvas.width,_.left=e,_.center=t,_.right=e,this._refreshDrawHeightConstants(),d.full=0,d.left=0,d.center=_.left,d.right=_.left+_.center}_refreshDrawHeightConstants(){c.full=Math.round(2*this._coreBrowseService.dpr);var e=this._canvas.height/this._bufferService.buffer.lines.length,e=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowseService.dpr);c.left=e,c.center=e,c.right=e}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=this._width+"px",this._canvas.width=Math.round(this._width*this._coreBrowseService.dpr),this._canvas.style.height=this._screenElement.clientHeight+"px",this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowseService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(const e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;const e=this._colorZoneStore.zones;for(const t of e)"full"!==t.position&&this._renderColorZone(t);for(const i of e)"full"===i.position&&this._renderColorZone(i);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(d[e.position||"full"],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-c[e.position||"full"]/2),_[e.position||"full"],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+c[e.position||"full"]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,void 0===this._animationFrame&&(this._animationFrame=this._coreBrowseService.window.requestAnimationFrame(()=>{this._refreshDecorations(),this._animationFrame=void 0}))}},i=s([r(2,l.IBufferService),r(3,l.IDecorationService),r(4,o.IRenderService),r(5,l.IOptionsService),r(6,o.ICoreBrowserService)],i);t.OverviewRulerRenderer=i},2950:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3{this._compositionPosition.end=this._textarea.value.length},0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(t){if(this._compositionView.classList.remove("active"),this._isComposing=!1,t){const t={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout(()=>{var e;this._isSendingComposition&&(this._isSendingComposition=!1,t.start+=this._dataAlreadySent.length,0<(e=this._isComposing?this._textarea.value.substring(t.start,t.end):this._textarea.value.substring(t.start)).length)&&this._coreService.triggerDataEvent(e,!0)},0)}else{this._isSendingComposition=!1;const t=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(t,!0)}}_handleAnyTextareaChanges(){const i=this._textarea.value;setTimeout(()=>{var e,t;this._isComposing||(t=(e=this._textarea.value).replace(i,""),this._dataAlreadySent=t,e.length>i.length?this._coreService.triggerDataEvent(t,!0):e.lengththis.updateCompositionElements(!0),0)}}},i=s([r(2,o.IBufferService),r(3,o.IOptionsService),r(4,o.ICoreService),r(5,n.IRenderService)],i);t.CompositionHelper=i},9806:(e,t)=>{function l(e,t,i){var s=i.getBoundingClientRect(),e=e.getComputedStyle(i),i=parseInt(e.getPropertyValue("padding-left")),e=parseInt(e.getPropertyValue("padding-top"));return[t.clientX-s.left-i,t.clientY-s.top-e]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=l,t.getCoords=function(e,t,i,s,r,n,o,a,h){return(n=n&&l(e,t,i))?(n[0]=Math.ceil((n[0]+(h?o/2:0))/o),n[1]=Math.ceil(n[1]/a),n[0]=Math.min(Math.max(n[0],1),s+(h?1:0)),n[1]=Math.min(Math.max(n[1],1),r),n):void 0}},9504:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;const s=i(2584);function f(e,t,i,s){var r=e-v(i,e),n=t-v(i,t);return S(Math.abs(r-n)-function(t,i,s){let r=0;const n=t-v(s,t),o=i-v(s,i);for(let e=0;en.cols-1?(h+=n.buffer.translateBufferLineToString(a,!1,e,o),e=o=0,a++):!r&&o<0&&(h+=n.buffer.translateBufferLineToString(a,!1,0,e+1),e=o=n.cols-1,a--);return h+n.buffer.translateBufferLineToString(a,!1,e,o)}function p(e,t){t=t?"O":"[";return s.C0.ESC+t+e}function S(t,i){t=Math.floor(t);let s="";for(let e=0;e{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;i=i(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=i.isFirefox||i.isLegacyEdge?"bottom":"ideographic"},1752:(e,t)=>{function i(e){return 57508<=e&&e<=57558}Object.defineProperty(t,"__esModule",{value:!0}),t.excludeFromContrastRatioDemands=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(e)return e;throw new Error("value must not be falsy")},t.isPowerlineGlyph=i,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.excludeFromContrastRatioDemands=function(e){return i(e)||9472<=e&&e<=9631}},1296:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._onLinkHover(e))),this.register(this._linkifier2.onHideLinkUnderline(e=>this._onLinkLeave(e)))}get onRequestRedraw(){return(new l.EventEmitter).event}dispose(){this._element.classList.remove(u+this._terminalClass),(0,d.removeElementFromParent)(this._rowContainer,this._selectionContainer,this._themeStyleElement,this._dimensionsStyleElement),super.dispose()}_updateDimensions(){const e=this._coreBrowserService.dpr;this.dimensions.scaledCharWidth=this._charSizeService.width*e,this.dimensions.scaledCharHeight=Math.ceil(this._charSizeService.height*e),this.dimensions.scaledCellWidth=this.dimensions.scaledCharWidth+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.scaledCellHeight=Math.floor(this.dimensions.scaledCharHeight*this._optionsService.rawOptions.lineHeight),this.dimensions.scaledCharLeft=0,this.dimensions.scaledCharTop=0,this.dimensions.scaledCanvasWidth=this.dimensions.scaledCellWidth*this._bufferService.cols,this.dimensions.scaledCanvasHeight=this.dimensions.scaledCellHeight*this._bufferService.rows,this.dimensions.canvasWidth=Math.round(this.dimensions.scaledCanvasWidth/e),this.dimensions.canvasHeight=Math.round(this.dimensions.scaledCanvasHeight/e),this.dimensions.actualCellWidth=this.dimensions.canvasWidth/this._bufferService.cols,this.dimensions.actualCellHeight=this.dimensions.canvasHeight/this._bufferService.rows;for(const e of this._rowElements)e.style.width=this.dimensions.canvasWidth+"px",e.style.height=this.dimensions.actualCellHeight+"px",e.style.lineHeight=this.dimensions.actualCellHeight+"px",e.style.overflow="hidden";this._dimensionsStyleElement||(this._dimensionsStyleElement=document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));var t=`${this._terminalSelector} .xterm-rows span { display: inline-block; height: 100%; vertical-align: top; width: ${this.dimensions.actualCellWidth}px}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=this.dimensions.canvasWidth+"px",this._screenElement.style.height=this.dimensions.canvasHeight+"px"}setColors(e){this._colors=e,this._injectCss()}_injectCss(){this._themeStyleElement||(this._themeStyleElement=document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));let i=`${this._terminalSelector} .xterm-rows { color: ${this._colors.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px;}`;i=(i=(i=(i=(i+=`${this._terminalSelector} span:not(.${c.BOLD_CLASS}) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.${c.BOLD_CLASS} { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.${c.ITALIC_CLASS} { font-style: italic;}`)+"@keyframes blink_box_shadow_"+this._terminalClass+" { 50% { box-shadow: none; }}")+"@keyframes blink_block_"+this._terminalClass+" { 0% {"+` background-color: ${this._colors.cursor.css};`+` color: ${this._colors.cursorAccent.css}; } 50% {`+` background-color: ${this._colors.cursorAccent.css};`+` color: ${this._colors.cursor.css}; }}`)+`${this._terminalSelector} .xterm-rows:not(.xterm-focus) .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_BLOCK_CLASS} { outline: 1px solid ${this._colors.cursor.css}; outline-offset: -1px;}${this._terminalSelector} .xterm-rows.xterm-focus .${c.CURSOR_CLASS}.${c.CURSOR_BLINK_CLASS}:not(.${c.CURSOR_STYLE_BLOCK_CLASS}) { animation: blink_box_shadow_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .xterm-rows.xterm-focus .${c.CURSOR_CLASS}.${c.CURSOR_BLINK_CLASS}.${c.CURSOR_STYLE_BLOCK_CLASS} { animation: blink_block_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .xterm-rows.xterm-focus .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_BLOCK_CLASS} {`+` background-color: ${this._colors.cursor.css};`+` color: ${this._colors.cursorAccent.css};}`+`${this._terminalSelector} .xterm-rows .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_BAR_CLASS} {`+` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${this._colors.cursor.css} inset;}`+`${this._terminalSelector} .xterm-rows .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_UNDERLINE_CLASS} {`+` box-shadow: 0 -1px 0 ${this._colors.cursor.css} inset;}`)+`${this._terminalSelector} .xterm-selection { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .xterm-selection div { position: absolute; background-color: ${this._colors.selectionBackgroundOpaque.css};}${this._terminalSelector} .xterm-selection div { position: absolute; background-color: ${this._colors.selectionInactiveBackgroundOpaque.css};}`,this._colors.ansi.forEach((e,t)=>{i+=`${this._terminalSelector} .xterm-fg-${t} { color: ${e.css}; }${this._terminalSelector} .xterm-bg-${t} { background-color: ${e.css}; }`}),i+=`${this._terminalSelector} .xterm-fg-${n.INVERTED_DEFAULT_COLOR} { color: ${_.color.opaque(this._colors.background).css}; }${this._terminalSelector} .xterm-bg-${n.INVERTED_DEFAULT_COLOR} { background-color: ${this._colors.foreground.css}; }`,this._themeStyleElement.textContent=i}onDevicePixelRatioChange(){this._updateDimensions()}_refreshRowElements(t,i){for(let e=this._rowElements.length;e<=i;e++){const t=document.createElement("div");this._rowContainer.appendChild(t),this._rowElements.push(t)}for(;this._rowElements.length>i;)this._rowContainer.removeChild(this._rowElements.pop())}onResize(e,t){this._refreshRowElements(e,t),this._updateDimensions()}onCharSizeChanged(){this._updateDimensions()}onBlur(){this._rowContainer.classList.remove(f)}onFocus(){this._rowContainer.classList.add(f)}onSelectionChanged(e,t,i){for(;this._selectionContainer.children.length;)this._selectionContainer.removeChild(this._selectionContainer.children[0]);if(this._rowFactory.onSelectionChanged(e,t,i),this.renderRows(0,this._bufferService.rows-1),e&&t){var s=e[1]-this._bufferService.buffer.ydisp,r=t[1]-this._bufferService.buffer.ydisp,n=Math.max(s,0),o=Math.min(r,this._bufferService.rows-1);if(!(n>=this._bufferService.rows||o<0)){var a=document.createDocumentFragment();if(i){const i=e[0]>t[0];a.appendChild(this._createSelectionElement(n,(i?t:e)[0],(i?e:t)[0],o-n+1))}else{const i=s===n?e[0]:0,h=n===r?t[0]:this._bufferService.cols;if(a.appendChild(this._createSelectionElement(n,i,h)),a.appendChild(this._createSelectionElement(n+1,0,this._bufferService.cols,o-n-1)),n!==o){const e=r===o?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(o,0,e))}}this._selectionContainer.appendChild(a)}}}_createSelectionElement(e,t,i,s=1){var r=document.createElement("div");return r.style.height=s*this.dimensions.actualCellHeight+"px",r.style.top=e*this.dimensions.actualCellHeight+"px",r.style.left=t*this.dimensions.actualCellWidth+"px",r.style.width=this.dimensions.actualCellWidth*(i-t)+"px",r}onCursorMove(){}onOptionsChanged(){this._updateDimensions(),this._injectCss()}clear(){for(const e of this._rowElements)e.innerText=""}renderRows(t,i){var s=this._bufferService.buffer.ybase+this._bufferService.buffer.y,r=Math.min(this._bufferService.buffer.x,this._bufferService.cols-1),n=this._optionsService.rawOptions.cursorBlink;for(let e=t;e<=i;e++){const t=this._rowElements[e],i=(t.innerText="",e+this._bufferService.buffer.ydisp),o=this._bufferService.buffer.lines.get(i),a=this._optionsService.rawOptions.cursorStyle;t.appendChild(this._rowFactory.createRow(o,i,i===s,a,r,n,this.dimensions.actualCellWidth,this._bufferService.cols))}}get _terminalSelector(){return"."+u+this._terminalClass}_onLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_onLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(e,t,i,s,r,n){for(;e!==t||i!==s;){const t=this._rowElements[i];if(!t)return;const s=t.children[e];s&&(s.style.textDecoration=n?"underline":"none"),++e>=r&&(e=0,i++)}}};g=s([r(5,h.IInstantiationService),r(6,a.ICharSizeService),r(7,h.IOptionsService),r(8,h.IBufferService),r(9,a.ICoreBrowserService)],g),t.DomRenderer=g},3787:function(e,L,t){var i=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3=d)&&p<=t&&(p=d),!this._coreService.isCursorHidden&&v&&d===p)switch(y.classList.add(L.CURSOR_CLASS),S&&y.classList.add(L.CURSOR_BLINK_CLASS),g){case"bar":y.classList.add(L.CURSOR_STYLE_BAR_CLASS);break;case"underline":y.classList.add(L.CURSOR_STYLE_UNDERLINE_CLASS);break;default:y.classList.add(L.CURSOR_STYLE_BLOCK_CLASS)}if(i.isBold()&&y.classList.add(L.BOLD_CLASS),i.isItalic()&&y.classList.add(L.ITALIC_CLASS),i.isDim()&&y.classList.add(L.DIM_CLASS),i.isInvisible()?y.textContent=k.WHITESPACE_CELL_CHAR:y.textContent=i.getChars()||k.WHITESPACE_CELL_CHAR,i.isUnderline()&&(y.classList.add(L.UNDERLINE_CLASS+"-"+i.extended.underlineStyle)," "===y.textContent&&(y.innerHTML=" "),!i.isUnderlineColorDefault()))if(i.isUnderlineColorRGB())y.style.textDecorationColor=`rgb(${x.AttributeData.toColorRGB(i.getUnderlineColor()).join(",")})`;else{let e=i.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&i.isBold()&&e<8&&(e+=8),y.style.textDecorationColor=this._colors.ansi[e].css}i.isStrikethrough()&&y.classList.add(L.STRIKETHROUGH_CLASS);let s=i.getFgColor(),r=i.getFgColorMode(),n=i.getBgColor(),o=i.getBgColorMode();var w=!!i.isInverse();if(w){const u=s,L=(s=n,n=u,r);r=o,o=L}let a,h,l=!1;this._decorationService.forEachDecorationAtCell(d,f,void 0,e=>{"top"!==e.options.layer&&l||(e.backgroundColorRGB&&(o=50331648,n=e.backgroundColorRGB.rgba>>8&16777215,a=e.backgroundColorRGB),e.foregroundColorRGB&&(r=50331648,s=e.foregroundColorRGB.rgba>>8&16777215,h=e.foregroundColorRGB),l="top"===e.options.layer)});var E=this._isCellInSelection(d,f);let c;switch(l||this._colors.selectionForeground&&E&&(r=50331648,s=this._colors.selectionForeground.rgba>>8&16777215,h=this._colors.selectionForeground),E&&(a=this._coreBrowserService.isFocused?this._colors.selectionBackgroundOpaque:this._colors.selectionInactiveBackgroundOpaque,l=!0),l&&y.classList.add("xterm-decoration-top"),o){case 16777216:case 33554432:c=this._colors.ansi[n],y.classList.add("xterm-bg-"+n);break;case 50331648:c=D.rgba.toColor(n>>16,n>>8&255,255&n),this._addStyle(y,"background-color:#"+B((n>>>0).toString(16),"0",6));break;default:w?(c=this._colors.foreground,y.classList.add("xterm-bg-"+R.INVERTED_DEFAULT_COLOR)):c=this._colors.background}switch(a||i.isDim()&&(a=D.color.multiplyOpacity(c,.5)),r){case 16777216:case 33554432:i.isBold()&&s<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&(s+=8),this._applyMinimumContrast(y,c,this._colors.ansi[s],i,a,void 0)||y.classList.add("xterm-fg-"+s);break;case 50331648:const u=D.rgba.toColor(s>>16&255,s>>8&255,255&s);this._applyMinimumContrast(y,c,u,i,a,h)||this._addStyle(y,"color:#"+B(s.toString(16),"0",6));break;default:this._applyMinimumContrast(y,c,this._colors.foreground,i,a,void 0)||w&&y.classList.add("xterm-fg-"+R.INVERTED_DEFAULT_COLOR)}C.appendChild(y),d=t}}return C}_applyMinimumContrast(e,t,i,s,r,n){if(1===this._optionsService.rawOptions.minimumContrastRatio||(0,h.excludeFromContrastRatioDemands)(s.getCode()))return!1;let o;return void 0===(o=r||n?o:this._colors.contrastCache.getColor(t.rgba,i.rgba))&&(o=D.color.ensureContrastRatio(r||t,n||i,this._optionsService.rawOptions.minimumContrastRatio),this._colors.contrastCache.setColor((r||t).rgba,(n||i).rgba,null!=o?o:null)),!!o&&(this._addStyle(e,"color:"+o.css),!0)}_addStyle(e,t){e.setAttribute("style",`${e.getAttribute("style")||""}${t};`)}_isCellInSelection(e,t){var i=this._selectionStart,s=this._selectionEnd;return!(!i||!s)&&(this._columnSelectMode?i[0]<=s[0]?e>=i[0]&&t>=i[1]&&e=i[1]&&e>=s[0]&&t<=s[1]:t>i[1]&&t=i[0]&&e=i[0])}};function B(e,t,i){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){var e;return this.isSelectAllActive?[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1]:this.selectionStart?!this.selectionEnd||this.areSelectionValuesReversed()?(e=this.selectionStart[0]+this.selectionStartLength)>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]:this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]?(e=this.selectionStart[0]+this.selectionStartLength)>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]:this.selectionEnd:void 0}areSelectionValuesReversed(){var e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}onTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0,t.CoreBrowserService=class{constructor(e,t){this._textarea=e,this.window=t}get dpr(){return this.window.devicePixelRatio}get isFocused(){return(this._textarea.getRootNode?this._textarea.getRootNode():this._textarea.ownerDocument).activeElement===this._textarea&&this._textarea.ownerDocument.hasFocus()}}},8934:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3=this._renderService.dimensions.canvasWidth||e[1]>=this._renderService.dimensions.canvasHeight))return{col:Math.floor(e[0]/this._renderService.dimensions.actualCellWidth),row:Math.floor(e[1]/this._renderService.dimensions.actualCellHeight),x:Math.floor(e[0]),y:Math.floor(e[1])}}},i=s([r(0,n.IRenderService),r(1,n.ICharSizeService)],i);t.MouseService=i},3230:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._renderer.dispose()}),this._renderDebouncer=new h.RenderDebouncer(a.window,(e,t)=>this._renderRows(e,t)),this.register(this._renderDebouncer),this._screenDprMonitor=new c.ScreenDprMonitor(a.window),this._screenDprMonitor.setListener(()=>this.onDevicePixelRatioChange()),this.register(this._screenDprMonitor),this.register(o.onResize(()=>this._fullRefresh())),this.register(o.buffers.onBufferActivate(()=>{var e;return null==(e=this._renderer)?void 0:e.clear()})),this.register(s.onOptionChange(()=>this._handleOptionsChanged())),this.register(this._charSizeService.onCharSizeChange(()=>this.onCharSizeChanged())),this.register(n.onDecorationRegistered(()=>this._fullRefresh())),this.register(n.onDecorationRemoved(()=>this._fullRefresh())),this._renderer.onRequestRedraw(e=>this.refreshRows(e.start,e.end,!0)),this.register((0,_.addDisposableDomListener)(a.window,"resize",()=>this.onDevicePixelRatioChange())),"IntersectionObserver"in a.window){const e=new a.window.IntersectionObserver(e=>this._onIntersectionChange(e[e.length-1]),{threshold:0});e.observe(i),this.register({dispose:()=>e.disconnect()})}}get onDimensionsChange(){return this._onDimensionsChange.event}get onRenderedViewportChange(){return this._onRenderedViewportChange.event}get onRender(){return this._onRender.event}get onRefreshRequest(){return this._onRefreshRequest.event}get dimensions(){return this._renderer.dimensions}_onIntersectionChange(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,i=!1){this._isPaused?this._needsFullRefresh=!0:(i||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.onSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.onOptionsChanged(),this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize()}_fireOnCanvasResize(){this._renderer.dimensions.canvasWidth===this._canvasWidth&&this._renderer.dimensions.canvasHeight===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.dimensions)}dispose(){super.dispose()}setRenderer(e){this._renderer.dispose(),this._renderer=e,this._renderer.onRequestRedraw(e=>this.refreshRows(e.start,e.end,!0)),this._needsSelectionRefresh=!0,this._fullRefresh()}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){var e,t;null!=(t=null==(e=this._renderer)?void 0:e.clearTextureAtlas)&&t.call(e),this._fullRefresh()}setColors(e){this._renderer.setColors(e),this._fullRefresh()}onDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.onDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1)}onResize(e,t){this._renderer.onResize(e,t),this._fullRefresh()}onCharSizeChanged(){this._renderer.onCharSizeChanged()}onBlur(){this._renderer.onBlur()}onFocus(){this._renderer.onFocus()}onSelectionChanged(e,t,i){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=i,this._renderer.onSelectionChanged(e,t,i)}onCursorMove(){this._renderer.onCursorMove()}clear(){this._renderer.clear()}},i=s([r(3,o.IOptionsService),r(4,a.ICharSizeService),r(5,o.IDecorationService),r(6,o.IBufferService),r(7,a.ICoreBrowserService)],i);t.RenderService=i},9312:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._onMouseMove(e),this._mouseUpListener=e=>this._onMouseUp(e),this._coreService.onUserInput(()=>{this.hasSelection&&this.clearSelection()}),this._trimListener=this._bufferService.buffer.lines.onTrim(e=>this._onTrim(e)),this.register(this._bufferService.buffers.onBufferActivate(e=>this._onBufferActivate(e))),this.enable(),this._model=new l.SelectionModel(this._bufferService),this._activeSelectionMode=0}get onLinuxMouseSelection(){return this._onLinuxMouseSelection.event}get onRequestRedraw(){return this._onRedrawRequest.event}get onSelectionChange(){return this._onSelectionChange.event}get onRequestScrollLines(){return this._onRequestScrollLines.event}dispose(){this._removeMouseDownListeners()}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){var e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){const t=this._model.finalSelectionStart,i=this._model.finalSelectionEnd;if(!t||!i)return"";var s=this._bufferService.buffer,r=[];if(3===this._activeSelectionMode){if(t[0]===i[0])return"";const n=(t[0]e.replace(g," ")).join(a.isWindows?"\r\n":"\n")}clearSelection(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()}refresh(e){this._refreshAnimationFrame||(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame(()=>this._refresh())),a.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)}_refresh(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})}_isClickInSelection(e){var e=this._getMouseBufferCoords(e),t=this._model.finalSelectionStart,i=this._model.finalSelectionEnd;return!!(t&&i&&e)&&this._areCoordsInSelection(e,t,i)}isCellInSelection(e,t){var i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!(!i||!s)&&this._areCoordsInSelection([e,t],i,s)}_areCoordsInSelection(e,t,i){return e[1]>t[1]&&e[1]=t[0]&&e[0]=t[0]}_selectWordAtCursor(e,t){var i=null==(i=null==(i=this._linkifier.currentLink)?void 0:i.link)?void 0:i.range;return i?(this._model.selectionStart=[i.start.x-1,i.start.y-1],this._model.selectionStartLength=(0,f.getRangeLength)(i,this._bufferService.cols),!(this._model.selectionEnd=void 0)):!!(i=this._getMouseBufferCoords(e))&&(this._selectWordAt(i,t),!(this._model.selectionEnd=void 0))}selectAll(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()}selectLines(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()}_onTrim(e){this._model.onTrim(e)&&this.refresh()}_getMouseBufferCoords(e){e=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(e)return e[0]--,e[1]--,e[1]+=this._bufferService.buffer.ydisp,e}_getMouseEventScrollAmount(e){let t=(0,h.getCoordsRelativeToElement)(this._coreBrowserService.window,e,this._screenElement)[1];e=this._renderService.dimensions.canvasHeight;return 0<=t&&t<=e?0:(t>e&&(t-=e),t=Math.min(Math.max(t,-50),50),(t/=50)/Math.abs(t)+Math.round(14*t))}shouldForceSelection(e){return a.isMac?e.altKey&&this._optionsService.rawOptions.macOptionClickForcesSelection:e.shiftKey}onMouseDown(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._onIncrementalClick(e):1===e.detail?this._onSingleClick(e):2===e.detail?this._onDoubleClick(e):3===e.detail&&this._onTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}}_addMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=this._coreBrowserService.window.setInterval(()=>this._dragScroll(),50)}_removeMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),this._coreBrowserService.window.clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0}_onIncrementalClick(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))}_onSingleClick(e){this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),this._model.selectionStart&&(this._model.selectionEnd=void 0,e=this._bufferService.buffer.lines.get(this._model.selectionStart[1]))&&e.length!==this._model.selectionStart[0]&&0===e.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}_onDoubleClick(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)}_onTripleClick(e){e=this._getMouseBufferCoords(e);e&&(this._activeSelectionMode=2,this._selectLineAt(e[1]))}shouldColumnSelect(e){return e.altKey&&!(a.isMac&&this._optionsService.rawOptions.macOptionClickForcesSelection)}_onMouseMove(e){if(e.stopImmediatePropagation(),this._model.selectionStart){var t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),this._model.selectionEnd){2===this._activeSelectionMode?this._model.selectionEnd[1]this._onTrim(e))}_convertViewportColToCharacterIndex(t,i){let s=i[0];for(let e=0;i[0]>=e;e++){var r=t.loadCell(e,this._workCell).getChars().length;0===this._workCell.getWidth()?s--:1=this._bufferService.cols)){var d=this._bufferService.buffer,u=d.lines.get(h[1]);if(u){var f=d.translateBufferLineToString(h[1],!1);let i=this._convertViewportColToCharacterIndex(u,h),s=i;var v=h[0]-i;let r=0,n=0,o=0,a=0;if(" "===f.charAt(i)){for(;0this._bufferService.cols;)i.length-=this._bufferService.cols,e++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?i.start:i.start+i.length,e]}}_isCharWordSeparator(e){return 0!==e.getWidth()&&0<=this._optionsService.rawOptions.wordSeparator.indexOf(e.getChars())}_selectLineAt(e){var e=this._bufferService.buffer.getWrappedRangeForLine(e),t={start:{x:0,y:e.first},end:{x:this._bufferService.cols-1,y:e.last}};this._model.selectionStart=[0,e.first],this._model.selectionEnd=void 0,this._model.selectionStartLength=(0,f.getRangeLength)(t,this._bufferService.cols)}},i=s([r(3,o.IBufferService),r(4,o.ICoreService),r(5,n.IMouseService),r(6,o.IOptionsService),r(7,n.IRenderService),r(8,n.ICoreBrowserService)],i);t.SelectionService=i},4725:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ICharacterJoinerService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;i=i(8343);t.ICharSizeService=(0,i.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,i.createDecorator)("CoreBrowserService"),t.IMouseService=(0,i.createDecorator)("MouseService"),t.IRenderService=(0,i.createDecorator)("RenderService"),t.ISelectionService=(0,i.createDecorator)("SelectionService"),t.ICharacterJoinerService=(0,i.createDecorator)("CharacterJoinerService")},6349:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;const s=i(8460);t.CircularList=class{constructor(e){this._maxLength=e,this.onDeleteEmitter=new s.EventEmitter,this.onInsertEmitter=new s.EventEmitter,this.onTrimEmitter=new s.EventEmitter,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}get onDelete(){return this.onDeleteEmitter.event}get onInsert(){return this.onInsertEmitter.event}get onTrim(){return this.onTrimEmitter.event}get maxLength(){return this._maxLength}set maxLength(t){if(this._maxLength!==t){var i=new Array(t);for(let e=0;ethis._length)for(let e=this._length;e=t;e--)this._array[this._getCyclicIndex(e+s.length)]=this._array[this._getCyclicIndex(e)];for(let e=0;ethis._maxLength){const t=this._length+s.length-this._maxLength;this._startIndex+=t,this._length=this._maxLength,this.onTrimEmitter.fire(t)}else this._length+=s.length}trimStart(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)}shiftElements(t,i,s){if(!(i<=0)){if(t<0||t>=this._length)throw new Error("start argument out of range");if(t+s<0)throw new Error("Cannot shift elements in list beyond index 0");if(0this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(let e=0;e{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,i=5){if("object"!=typeof t)return t;var s=Array.isArray(t)?[]:{};for(const r in t)s[r]=i<=1?t[r]:t[r]&&e(t[r],i-1);return s}},8055:(e,t)=>{var a,c,_,i;function r(e){e=e.toString(16);return e.length<2?"0"+e:e}function d(e,t){return e>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,l=d(c.relativeLuminance2(o,a,h),c.relativeLuminance2(s,r,n));for(;l>>0}function l(e,t,i){var s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,l=d(c.relativeLuminance2(o,a,h),c.relativeLuminance2(s,r,n));for(;l>>0}function s(e,t,i){e/=255,t/=255,i/=255;return.2126*(e<=.03928?e/12.92:Math.pow((.055+e)/1.055,2.4))+.7152*(t<=.03928?t/12.92:Math.pow((.055+t)/1.055,2.4))+.0722*(i<=.03928?i/12.92:Math.pow((.055+i)/1.055,2.4))}function n(e,t){var t=Math.round(255*t),[e,i,s]=_.toChannels(e.rgba);return{css:a.toCss(e,i,s,t),rgba:a.toRgba(e,i,s,t)}}Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=void 0,(i=a=t.channels||(t.channels={})).toCss=function(e,t,i,s){return void 0!==s?"#"+r(e)+r(t)+r(i)+r(s):"#"+r(e)+r(t)+r(i)},i.toRgba=function(e,t,i,s=255){return(e<<24|t<<16|i<<8|s)>>>0},(i=t.color||(t.color={})).blend=function(e,t){var i,s,r,n,o=(255&t.rgba)/255;return 1==o?{css:t.css,rgba:t.rgba}:(s=t.rgba>>24&255,n=t.rgba>>16&255,t=t.rgba>>8&255,r=e.rgba>>24&255,i=e.rgba>>16&255,e=e.rgba>>8&255,s=r+Math.round((s-r)*o),r=i+Math.round((n-i)*o),n=e+Math.round((t-e)*o),{css:a.toCss(s,r,n),rgba:a.toRgba(s,r,n)})},i.isOpaque=function(e){return 255==(255&e.rgba)},i.ensureContrastRatio=function(e,t,i){e=_.ensureContrastRatio(e.rgba,t.rgba,i);if(e)return _.toColor(e>>24&255,e>>16&255,e>>8&255)},i.opaque=function(e){var e=(255|e.rgba)>>>0,[t,i,s]=_.toChannels(e);return{css:a.toCss(t,i,s),rgba:e}},i.opacity=n,i.multiplyOpacity=function(e,t){return n(e,(255&e.rgba)*t/255)},i.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]},(t.css||(t.css={})).toColor=function(e){if(e.match(/#[0-9a-f]{3,8}/i))switch(e.length){case 4:{const t=parseInt(e.slice(1,2).repeat(2),16),i=parseInt(e.slice(2,3).repeat(2),16),s=parseInt(e.slice(3,4).repeat(2),16);return _.toColor(t,i,s)}case 5:{const t=parseInt(e.slice(1,2).repeat(2),16),r=parseInt(e.slice(2,3).repeat(2),16),n=parseInt(e.slice(3,4).repeat(2),16),o=parseInt(e.slice(4,5).repeat(2),16);return _.toColor(t,r,n,o)}case 7:return{css:e,rgba:(parseInt(e.slice(1),16)<<8|255)>>>0};case 9:return{css:e,rgba:parseInt(e.slice(1),16)>>>0}}const t=e.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);if(t){const e=parseInt(t[1]),a=parseInt(t[2]),h=parseInt(t[3]),l=Math.round(255*(void 0===t[5]?1:parseFloat(t[5])));return _.toColor(e,a,h,l)}throw new Error("css.toColor: Unsupported css format")},(i=c=t.rgb||(t.rgb={})).relativeLuminance=function(e){return s(e>>16&255,e>>8&255,255&e)},i.relativeLuminance2=s,(i=_=t.rgba||(t.rgba={})).ensureContrastRatio=function(e,t,i){const s=c.relativeLuminance(e>>8),r=c.relativeLuminance(t>>8);if(d(s,r)>8));if(ad(s,c.relativeLuminance(h>>8))?r:h}return r}var n=l(e,t,i),o=d(s,c.relativeLuminance(n>>8));if(od(s,c.relativeLuminance(l>>8))?n:l}return n}},i.reduceLuminance=h,i.increaseLuminance=l,i.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},i.toColor=function(e,t,i,s){return{css:a.toCss(e,t,i,s),rgba:a.toRgba(e,t,i,s)}},t.toPaddedHex=r,t.contrastRatio=d},8969:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;const s=i(844),r=i(2585),n=i(4348),o=i(7866),a=i(744),h=i(7302),l=i(6975),c=i(8460),_=i(1753),d=i(3730),u=i(1480),f=i(7994),v=i(9282),g=i(5435),p=i(5981),S=i(2660);let m=!1;class C extends s.Disposable{constructor(e){super(),this._onBinary=new c.EventEmitter,this._onData=new c.EventEmitter,this._onLineFeed=new c.EventEmitter,this._onResize=new c.EventEmitter,this._onScroll=new c.EventEmitter,this._onWriteParsed=new c.EventEmitter,this._instantiationService=new n.InstantiationService,this.optionsService=new h.OptionsService(e),this._instantiationService.setService(r.IOptionsService,this.optionsService),this._bufferService=this.register(this._instantiationService.createInstance(a.BufferService)),this._instantiationService.setService(r.IBufferService,this._bufferService),this._logService=this._instantiationService.createInstance(o.LogService),this._instantiationService.setService(r.ILogService,this._logService),this.coreService=this.register(this._instantiationService.createInstance(l.CoreService,()=>this.scrollToBottom())),this._instantiationService.setService(r.ICoreService,this.coreService),this.coreMouseService=this._instantiationService.createInstance(_.CoreMouseService),this._instantiationService.setService(r.ICoreMouseService,this.coreMouseService),this._dirtyRowService=this._instantiationService.createInstance(d.DirtyRowService),this._instantiationService.setService(r.IDirtyRowService,this._dirtyRowService),this.unicodeService=this._instantiationService.createInstance(u.UnicodeService),this._instantiationService.setService(r.IUnicodeService,this.unicodeService),this._charsetService=this._instantiationService.createInstance(f.CharsetService),this._instantiationService.setService(r.ICharsetService,this._charsetService),this._oscLinkService=this._instantiationService.createInstance(S.OscLinkService),this._instantiationService.setService(r.IOscLinkService,this._oscLinkService),this._inputHandler=new g.InputHandler(this._bufferService,this._charsetService,this.coreService,this._dirtyRowService,this._logService,this.optionsService,this._oscLinkService,this.coreMouseService,this.unicodeService),this.register((0,c.forwardEvent)(this._inputHandler.onLineFeed,this._onLineFeed)),this.register(this._inputHandler),this.register((0,c.forwardEvent)(this._bufferService.onResize,this._onResize)),this.register((0,c.forwardEvent)(this.coreService.onData,this._onData)),this.register((0,c.forwardEvent)(this.coreService.onBinary,this._onBinary)),this.register(this.optionsService.onOptionChange(e=>this._updateOptions(e))),this.register(this._bufferService.onScroll(e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)})),this.register(this._inputHandler.onScroll(e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)})),this._writeBuffer=new p.WriteBuffer((e,t)=>this._inputHandler.parse(e,t)),this.register((0,c.forwardEvent)(this._writeBuffer.onWriteParsed,this._onWriteParsed))}get onBinary(){return this._onBinary.event}get onData(){return this._onData.event}get onLineFeed(){return this._onLineFeed.event}get onResize(){return this._onResize.event}get onWriteParsed(){return this._onWriteParsed.event}get onScroll(){return this._onScrollApi||(this._onScrollApi=new c.EventEmitter,this.register(this._onScroll.event(e=>{var t;null!=(t=this._onScrollApi)&&t.fire(e.position)}))),this._onScrollApi.event}get cols(){return this._bufferService.cols}get rows(){return this._bufferService.rows}get buffers(){return this._bufferService.buffers}get options(){return this.optionsService.options}set options(e){for(const t in e)this.optionsService.options[t]=e[t]}dispose(){var e;this._isDisposed||(super.dispose(),null!=(e=this._windowsMode)&&e.dispose(),this._windowsMode=void 0)}write(e,t){this._writeBuffer.write(e,t)}writeSync(e,t){this._logService.logLevel<=r.LogLevelEnum.WARN&&!m&&(this._logService.warn("writeSync is unreliable and will be removed soon."),m=!0),this._writeBuffer.writeSync(e,t)}resize(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,a.MINIMUM_COLS),t=Math.max(t,a.MINIMUM_ROWS),this._bufferService.resize(e,t))}scroll(e,t=!1){this._bufferService.scroll(e,t)}scrollLines(e,t,i){this._bufferService.scrollLines(e,t,i)}scrollPages(e){this._bufferService.scrollPages(e)}scrollToTop(){this._bufferService.scrollToTop()}scrollToBottom(){this._bufferService.scrollToBottom()}scrollToLine(e){this._bufferService.scrollToLine(e)}registerEscHandler(e,t){return this._inputHandler.registerEscHandler(e,t)}registerDcsHandler(e,t){return this._inputHandler.registerDcsHandler(e,t)}registerCsiHandler(e,t){return this._inputHandler.registerCsiHandler(e,t)}registerOscHandler(e,t){return this._inputHandler.registerOscHandler(e,t)}_setup(){this.optionsService.rawOptions.windowsMode&&this._enableWindowsMode()}reset(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()}_updateOptions(e){var t;switch(e){case"scrollback":this.buffers.resize(this.cols,this.rows);break;case"windowsMode":this.optionsService.rawOptions.windowsMode?this._enableWindowsMode():(null!=(t=this._windowsMode)&&t.dispose(),this._windowsMode=void 0)}}_enableWindowsMode(){if(!this._windowsMode){const t=[];t.push(this.onLineFeed(v.updateWindowsModeWrappedState.bind(null,this._bufferService))),t.push(this.registerCsiHandler({final:"H"},()=>((0,v.updateWindowsModeWrappedState)(this._bufferService),!1))),this._windowsMode={dispose:()=>{for(const e of t)e.dispose()}}}}}t.CoreTerminal=C},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=t=>(this._listeners.push(t),{dispose:()=>{if(!this._disposed)for(let e=0;et.fire(e))}},5435:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;const d=i(2584),c=i(7116),_=i(2015),s=i(844),u=i(482),f=i(8437),v=i(8460),g=i(643),p=i(511),n=i(3734),a=i(2585),S=i(6242),m=i(6351),r=i(5941),o={"(":0,")":1,"*":2,"+":3,"-":1,".":2},h=131072;function l(e,t){if(24this._activeBuffer=e.activeBuffer)),this._parser.setCsiHandlerFallback((e,t)=>{this._logService.debug("Unknown CSI code: ",{identifier:this._parser.identToString(e),params:t.toArray()})}),this._parser.setEscHandlerFallback(e=>{this._logService.debug("Unknown ESC code: ",{identifier:this._parser.identToString(e)})}),this._parser.setExecuteHandlerFallback(e=>{this._logService.debug("Unknown EXECUTE code: ",{code:e})}),this._parser.setOscHandlerFallback((e,t,i)=>{this._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:i})}),this._parser.setDcsHandlerFallback((e,t,i)=>{"HOOK"===t&&(i=i.toArray()),this._logService.debug("Unknown DCS code: ",{identifier:this._parser.identToString(e),action:t,payload:i})}),this._parser.setPrintHandler((e,t,i)=>this.print(e,t,i)),this._parser.registerCsiHandler({final:"@"},e=>this.insertChars(e)),this._parser.registerCsiHandler({intermediates:" ",final:"@"},e=>this.scrollLeft(e)),this._parser.registerCsiHandler({final:"A"},e=>this.cursorUp(e)),this._parser.registerCsiHandler({intermediates:" ",final:"A"},e=>this.scrollRight(e)),this._parser.registerCsiHandler({final:"B"},e=>this.cursorDown(e)),this._parser.registerCsiHandler({final:"C"},e=>this.cursorForward(e)),this._parser.registerCsiHandler({final:"D"},e=>this.cursorBackward(e)),this._parser.registerCsiHandler({final:"E"},e=>this.cursorNextLine(e)),this._parser.registerCsiHandler({final:"F"},e=>this.cursorPrecedingLine(e)),this._parser.registerCsiHandler({final:"G"},e=>this.cursorCharAbsolute(e)),this._parser.registerCsiHandler({final:"H"},e=>this.cursorPosition(e)),this._parser.registerCsiHandler({final:"I"},e=>this.cursorForwardTab(e)),this._parser.registerCsiHandler({final:"J"},e=>this.eraseInDisplay(e,!1)),this._parser.registerCsiHandler({prefix:"?",final:"J"},e=>this.eraseInDisplay(e,!0)),this._parser.registerCsiHandler({final:"K"},e=>this.eraseInLine(e,!1)),this._parser.registerCsiHandler({prefix:"?",final:"K"},e=>this.eraseInLine(e,!0)),this._parser.registerCsiHandler({final:"L"},e=>this.insertLines(e)),this._parser.registerCsiHandler({final:"M"},e=>this.deleteLines(e)),this._parser.registerCsiHandler({final:"P"},e=>this.deleteChars(e)),this._parser.registerCsiHandler({final:"S"},e=>this.scrollUp(e)),this._parser.registerCsiHandler({final:"T"},e=>this.scrollDown(e)),this._parser.registerCsiHandler({final:"X"},e=>this.eraseChars(e)),this._parser.registerCsiHandler({final:"Z"},e=>this.cursorBackwardTab(e)),this._parser.registerCsiHandler({final:"`"},e=>this.charPosAbsolute(e)),this._parser.registerCsiHandler({final:"a"},e=>this.hPositionRelative(e)),this._parser.registerCsiHandler({final:"b"},e=>this.repeatPrecedingCharacter(e)),this._parser.registerCsiHandler({final:"c"},e=>this.sendDeviceAttributesPrimary(e)),this._parser.registerCsiHandler({prefix:">",final:"c"},e=>this.sendDeviceAttributesSecondary(e)),this._parser.registerCsiHandler({final:"d"},e=>this.linePosAbsolute(e)),this._parser.registerCsiHandler({final:"e"},e=>this.vPositionRelative(e)),this._parser.registerCsiHandler({final:"f"},e=>this.hVPosition(e)),this._parser.registerCsiHandler({final:"g"},e=>this.tabClear(e)),this._parser.registerCsiHandler({final:"h"},e=>this.setMode(e)),this._parser.registerCsiHandler({prefix:"?",final:"h"},e=>this.setModePrivate(e)),this._parser.registerCsiHandler({final:"l"},e=>this.resetMode(e)),this._parser.registerCsiHandler({prefix:"?",final:"l"},e=>this.resetModePrivate(e)),this._parser.registerCsiHandler({final:"m"},e=>this.charAttributes(e)),this._parser.registerCsiHandler({final:"n"},e=>this.deviceStatus(e)),this._parser.registerCsiHandler({prefix:"?",final:"n"},e=>this.deviceStatusPrivate(e)),this._parser.registerCsiHandler({intermediates:"!",final:"p"},e=>this.softReset(e)),this._parser.registerCsiHandler({intermediates:" ",final:"q"},e=>this.setCursorStyle(e)),this._parser.registerCsiHandler({final:"r"},e=>this.setScrollRegion(e)),this._parser.registerCsiHandler({final:"s"},e=>this.saveCursor(e)),this._parser.registerCsiHandler({final:"t"},e=>this.windowOptions(e)),this._parser.registerCsiHandler({final:"u"},e=>this.restoreCursor(e)),this._parser.registerCsiHandler({intermediates:"'",final:"}"},e=>this.insertColumns(e)),this._parser.registerCsiHandler({intermediates:"'",final:"~"},e=>this.deleteColumns(e)),this._parser.registerCsiHandler({intermediates:'"',final:"q"},e=>this.selectProtected(e)),this._parser.registerCsiHandler({intermediates:"$",final:"p"},e=>this.requestMode(e,!0)),this._parser.registerCsiHandler({prefix:"?",intermediates:"$",final:"p"},e=>this.requestMode(e,!1)),this._parser.setExecuteHandler(d.C0.BEL,()=>this.bell()),this._parser.setExecuteHandler(d.C0.LF,()=>this.lineFeed()),this._parser.setExecuteHandler(d.C0.VT,()=>this.lineFeed()),this._parser.setExecuteHandler(d.C0.FF,()=>this.lineFeed()),this._parser.setExecuteHandler(d.C0.CR,()=>this.carriageReturn()),this._parser.setExecuteHandler(d.C0.BS,()=>this.backspace()),this._parser.setExecuteHandler(d.C0.HT,()=>this.tab()),this._parser.setExecuteHandler(d.C0.SO,()=>this.shiftOut()),this._parser.setExecuteHandler(d.C0.SI,()=>this.shiftIn()),this._parser.setExecuteHandler(d.C1.IND,()=>this.index()),this._parser.setExecuteHandler(d.C1.NEL,()=>this.nextLine()),this._parser.setExecuteHandler(d.C1.HTS,()=>this.tabSet()),this._parser.registerOscHandler(0,new S.OscHandler(e=>(this.setTitle(e),this.setIconName(e),!0))),this._parser.registerOscHandler(1,new S.OscHandler(e=>this.setIconName(e))),this._parser.registerOscHandler(2,new S.OscHandler(e=>this.setTitle(e))),this._parser.registerOscHandler(4,new S.OscHandler(e=>this.setOrReportIndexedColor(e))),this._parser.registerOscHandler(8,new S.OscHandler(e=>this.setHyperlink(e))),this._parser.registerOscHandler(10,new S.OscHandler(e=>this.setOrReportFgColor(e))),this._parser.registerOscHandler(11,new S.OscHandler(e=>this.setOrReportBgColor(e))),this._parser.registerOscHandler(12,new S.OscHandler(e=>this.setOrReportCursorColor(e))),this._parser.registerOscHandler(104,new S.OscHandler(e=>this.restoreIndexedColor(e))),this._parser.registerOscHandler(110,new S.OscHandler(e=>this.restoreFgColor(e))),this._parser.registerOscHandler(111,new S.OscHandler(e=>this.restoreBgColor(e))),this._parser.registerOscHandler(112,new S.OscHandler(e=>this.restoreCursorColor(e))),this._parser.registerEscHandler({final:"7"},()=>this.saveCursor()),this._parser.registerEscHandler({final:"8"},()=>this.restoreCursor()),this._parser.registerEscHandler({final:"D"},()=>this.index()),this._parser.registerEscHandler({final:"E"},()=>this.nextLine()),this._parser.registerEscHandler({final:"H"},()=>this.tabSet()),this._parser.registerEscHandler({final:"M"},()=>this.reverseIndex()),this._parser.registerEscHandler({final:"="},()=>this.keypadApplicationMode()),this._parser.registerEscHandler({final:">"},()=>this.keypadNumericMode()),this._parser.registerEscHandler({final:"c"},()=>this.fullReset()),this._parser.registerEscHandler({final:"n"},()=>this.setgLevel(2)),this._parser.registerEscHandler({final:"o"},()=>this.setgLevel(3)),this._parser.registerEscHandler({final:"|"},()=>this.setgLevel(3)),this._parser.registerEscHandler({final:"}"},()=>this.setgLevel(2)),this._parser.registerEscHandler({final:"~"},()=>this.setgLevel(1)),this._parser.registerEscHandler({intermediates:"%",final:"@"},()=>this.selectDefaultCharset()),this._parser.registerEscHandler({intermediates:"%",final:"G"},()=>this.selectDefaultCharset());for(const e in c.CHARSETS)this._parser.registerEscHandler({intermediates:"(",final:e},()=>this.selectCharset("("+e)),this._parser.registerEscHandler({intermediates:")",final:e},()=>this.selectCharset(")"+e)),this._parser.registerEscHandler({intermediates:"*",final:e},()=>this.selectCharset("*"+e)),this._parser.registerEscHandler({intermediates:"+",final:e},()=>this.selectCharset("+"+e)),this._parser.registerEscHandler({intermediates:"-",final:e},()=>this.selectCharset("-"+e)),this._parser.registerEscHandler({intermediates:".",final:e},()=>this.selectCharset("."+e)),this._parser.registerEscHandler({intermediates:"/",final:e},()=>this.selectCharset("/"+e));this._parser.registerEscHandler({intermediates:"#",final:"8"},()=>this.screenAlignmentPattern()),this._parser.setErrorHandler(e=>(this._logService.error("Parsing error: ",e),e)),this._parser.registerDcsHandler({intermediates:"$",final:"q"},new m.DcsHandler((e,t)=>this.requestStatusString(e,t)))}getAttrData(){return this._curAttrData}get onRequestBell(){return this._onRequestBell.event}get onRequestRefreshRows(){return this._onRequestRefreshRows.event}get onRequestReset(){return this._onRequestReset.event}get onRequestSendFocus(){return this._onRequestSendFocus.event}get onRequestSyncScrollBar(){return this._onRequestSyncScrollBar.event}get onRequestWindowsOptionsReport(){return this._onRequestWindowsOptionsReport.event}get onA11yChar(){return this._onA11yChar.event}get onA11yTab(){return this._onA11yTab.event}get onCursorMove(){return this._onCursorMove.event}get onLineFeed(){return this._onLineFeed.event}get onScroll(){return this._onScroll.event}get onTitleChange(){return this._onTitleChange.event}get onColor(){return this._onColor.event}dispose(){super.dispose()}_preserveStack(e,t,i,s){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=i,this._parseStack.position=s}_logSlowResolvingAsync(e){this._logService.logLevel<=a.LogLevelEnum.WARN&&Promise.race([e,new Promise((e,t)=>setTimeout(()=>t("#SLOW_TIMEOUT"),5e3))]).catch(e=>{if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")})}parse(t,e){let i,s=this._activeBuffer.x,r=this._activeBuffer.y,n=0;const o=this._parseStack.paused;if(o){if(i=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,e))return this._logSlowResolvingAsync(i),i;s=this._parseStack.cursorStartX,r=this._parseStack.cursorStartY,this._parseStack.paused=!1,t.length>h&&(n=this._parseStack.position+h)}if(this._logService.logLevel<=a.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof t?` "${t}"`:` "${Array.prototype.map.call(t,e=>String.fromCharCode(e)).join("")}"`),"string"==typeof t?t.split("").map(e=>e.charCodeAt(0)):t),this._parseBuffer.lengthh)for(let e=n;e=h)if(l){for(;this._activeBuffer.x=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),d=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)}else if(this._activeBuffer.x=h-1,2===n)continue;if(c&&(d.insertCells(this._activeBuffer.x,n,this._activeBuffer.getNullCell(_),_),2===d.getWidth(h-1))&&d.setCellFromCodePoint(h-1,g.NULL_CELL_CODE,g.NULL_CELL_WIDTH,_.fg,_.bg,_.extended),d.setCellFromCodePoint(this._activeBuffer.x++,r,n,_.fg,_.bg,_.extended),0!l(e.params[0],this._optionsService.rawOptions.windowOptions)||t(e))}registerDcsHandler(e,t){return this._parser.registerDcsHandler(e,new m.DcsHandler(t))}registerEscHandler(e,t){return this._parser.registerEscHandler(e,t)}registerOscHandler(e,t){return this._parser.registerOscHandler(e,new S.OscHandler(t))}bell(){return this._onRequestBell.fire(),!0}lineFeed(){return this._dirtyRowService.markDirty(this._activeBuffer.y),this._optionsService.rawOptions.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowService.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0}carriageReturn(){return!(this._activeBuffer.x=0)}backspace(){var e;if(this._coreService.decPrivateModes.reverseWraparound){if(this._restrictCursor(this._bufferService.cols),0this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&null!=(e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y))&&e.isWrapped){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;const e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);e.hasWidth(this._activeBuffer.x)&&!e.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}this._restrictCursor()}else this._restrictCursor(),0=this._bufferService.cols||(e=this._activeBuffer.x,this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.rawOptions.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e)),!0}shiftOut(){return this._charsetService.setgLevel(1),!0}shiftIn(){return this._charsetService.setgLevel(0),!0}_restrictCursor(e=this._bufferService.cols-1){this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowService.markDirty(this._activeBuffer.y)}_setCursor(e,t){this._dirtyRowService.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowService.markDirty(this._activeBuffer.y)}_moveCursor(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)}cursorUp(e){var t=this._activeBuffer.y-this._activeBuffer.scrollTop;return 0<=t?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0}cursorDown(e){var t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return 0<=t?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0}cursorForward(e){return this._moveCursor(e.params[0]||1,0),!0}cursorBackward(e){return this._moveCursor(-(e.params[0]||1),0),!0}cursorNextLine(e){return this.cursorDown(e),!(this._activeBuffer.x=0)}cursorPrecedingLine(e){return this.cursorUp(e),!(this._activeBuffer.x=0)}cursorCharAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}cursorPosition(e){return this._setCursor(2<=e.length?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0}charPosAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}hPositionRelative(e){return this._moveCursor(e.params[0]||1,0),!0}linePosAbsolute(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0}vPositionRelative(e){return this._moveCursor(0,e.params[0]||1),!0}hVPosition(e){return this.cursorPosition(e),!0}tabClear(e){e=e.params[0];return 0===e?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===e&&(this._activeBuffer.tabs={}),!0}cursorForwardTab(t){if(!(this._activeBuffer.x>=this._bufferService.cols)){let e=t.params[0]||1;for(;e--;)this._activeBuffer.x=this._activeBuffer.nextStop()}return!0}cursorBackwardTab(t){if(!(this._activeBuffer.x>=this._bufferService.cols)){let e=t.params[0]||1;for(;e--;)this._activeBuffer.x=this._activeBuffer.prevStop()}return!0}selectProtected(e){e=e.params[0];return 1===e&&(this._curAttrData.bg|=536870912),2!==e&&0!==e||(this._curAttrData.bg&=-536870913),!0}_eraseInBufferLine(e,t,i,s=!1,r=!1){e=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);e.replaceCells(t,i,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData(),r),s&&(e.isWrapped=!1)}_resetBufferLine(e,t=!1){var i=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);i.fill(this._activeBuffer.getNullCell(this._eraseAttrData()),t),this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase+e),i.isWrapped=!1}eraseInDisplay(e,t=!1){let i;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(i=this._activeBuffer.y,this._dirtyRowService.markDirty(i),this._eraseInBufferLine(i++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);i=this._bufferService.cols&&(this._activeBuffer.lines.get(i+1).isWrapped=!1);i--;)this._resetBufferLine(i,t);this._dirtyRowService.markDirty(0);break;case 2:for(i=this._bufferService.rows,this._dirtyRowService.markDirty(i-1);i--;)this._resetBufferLine(i,t);this._dirtyRowService.markDirty(0);break;case 3:const e=this._activeBuffer.lines.length-this._bufferService.rows;0this._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.y0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(d.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(d.C0.ESC+"[>83;40003;0c")),!0}_is(e){return 0===(this._optionsService.rawOptions.termName+"").indexOf(e)}setMode(t){for(let e=0;ee?1:2,e=e.params[0],_=e,a=t?2===e?3:4===e?c(n.modes.insertMode):12===e?4:20===e?c(l.convertEol):0:1===e?c(i.applicationCursorKeys):3===e?l.windowOptions.setWinLines?80===a?2:132===a?1:0:0:6===e?c(i.origin):7===e?c(i.wraparound):8===e?3:9===e?"X10"===s?1:2:12===e?c(l.cursorBlink):25===e?c(!n.isCursorHidden):45===e?c(i.reverseWraparound):66===e?c(i.applicationKeypad):1e3===e?"VT200"===s?1:2:1002===e?"DRAG"===s?1:2:1003===e?"ANY"===s?1:2:1004===e?c(i.sendFocus):1005===e?4:1006===e?"SGR"===r?1:2:1015===e?4:1016===e?"SGR_PIXELS"===r?1:2:1048===e?1:47===e||1047===e||1049===e?o===h?1:2:2004===e?c(i.bracketedPasteMode):0;return n.triggerDataEvent(d.C0.ESC+`[${t?"":"?"}${_};${a}$y`),!0}_updateAttrColor(e,t,i,s,r){return 2===t?e=(e=(e|50331648)&-16777216)|n.AttributeData.fromColorRGB([i,s,r]):5===t&&(e=e&-50331904|(33554432|255&i)),e}_extractColor(t,i,s){var r=[0,0,-1,0,0,0];let n=0,o=0;do{if(r[o+n]=t.params[i+o],t.hasSubParams(i+o)){const s=t.getSubParams(i+o);let e=0;for(;5===r[1]&&(n=1),r[o+e+1+n]=s[e],++ethis._bufferService.rows||0===i?this._bufferService.rows:i)>t&&(this._activeBuffer.scrollTop=t-1,this._activeBuffer.scrollBottom=i-1,this._setCursor(0,0)),!0}windowOptions(e){if(l(e.params[0],this._optionsService.rawOptions.windowOptions)){var t=1e.startsWith("id="));return-1!==s&&(i=e[s].slice(3)||void 0),this._curAttrData.extended=this._curAttrData.extended.clone(),this._currentLinkId=this._oscLinkService.registerLink({id:i,uri:t}),this._curAttrData.extended.urlId=this._currentLinkId,this._curAttrData.updateExtended(),!0}_finishHyperlink(){return this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=0,this._curAttrData.updateExtended(),!(this._currentLinkId=void 0)}_setOrReportSpecialColor(e,t){var i,s=e.split(";");for(let e=0;e=this._specialColors.length);++e,++t)"?"===s[e]?this._onColor.fire([{type:0,index:this._specialColors[t]}]):(i=(0,r.parseColor)(s[e]))&&this._onColor.fire([{type:1,index:this._specialColors[t],color:i}]);return!0}setOrReportFgColor(e){return this._setOrReportSpecialColor(e,0)}setOrReportBgColor(e){return this._setOrReportSpecialColor(e,1)}setOrReportCursorColor(e){return this._setOrReportSpecialColor(e,2)}restoreIndexedColor(e){if(e){var t,i=[],s=e.split(";");for(let e=0;e=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0}tabSet(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0}reverseIndex(){var e;return this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop?(e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop,this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)):(this._activeBuffer.y--,this._restrictCursor()),!0}fullReset(){return this._parser.reset(),this._onRequestReset.fire(),!0}reset(){this._curAttrData=f.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=f.DEFAULT_ATTR_DATA.clone()}_eraseAttrData(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal}setgLevel(e){return this._charsetService.setgLevel(e),!0}screenAlignmentPattern(){var t=new p.CellData;t.content=1<<22|"E".charCodeAt(0),t.fg=this._curAttrData.fg,t.bg=this._curAttrData.bg,this._setCursor(0,0);for(let e=0;e{function i(e){for(const t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){e=this._disposables.indexOf(e);-1!==e&&this._disposables.splice(e,1)}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}},1505:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FourKeyMap=t.TwoKeyMap=void 0;class n{constructor(){this._data={}}set(e,t,i){this._data[e]||(this._data[e]={}),this._data[e][t]=i}get(e,t){return this._data[e]?this._data[e][t]:void 0}clear(){this._data={}}}t.TwoKeyMap=n,t.FourKeyMap=class{constructor(){this._data=new n}set(e,t,i,s,r){this._data.get(e,t)||this._data.set(e,t,new n),this._data.get(e,t).set(i,s,r)}get(e,t,i,s){return null==(e=this._data.get(e,t))?void 0:e.get(i,s)}clear(){this._data.clear()}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.isSafari=t.isLegacyEdge=t.isFirefox=void 0;var i="undefined"==typeof navigator,s=i?"node":navigator.userAgent,i=i?"node":navigator.platform;t.isFirefox=s.includes("Firefox"),t.isLegacyEdge=s.includes("Edge"),t.isSafari=/^((?!chrome|android).)*safari/i.test(s),t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(i),t.isIpad="iPad"===i,t.isIphone="iPhone"===i,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(i),t.isLinux=0<=i.indexOf("Linux")},6106:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SortedList=void 0;let i=0;t.SortedList=class{constructor(e){this._getKey=e,this._array=[]}clear(){this._array.length=0}insert(e){0!==this._array.length?(i=this._search(this._getKey(e),0,this._array.length-1),this._array.splice(i,0,e)):this._array.push(e)}delete(e){if(0!==this._array.length){var t=this._getKey(e);if(void 0!==t&&-1!==(i=this._search(t,0,this._array.length-1))&&this._getKey(this._array[i])===t)do{if(this._array[i]===e)return this._array.splice(i,1),!0}while(++i=this._array.length)&&this._getKey(this._array[i])===e)for(;yield this._array[i],++i=this._array.length)&&this._getKey(this._array[i])===e)for(;t(this._array[i]),++i{function r(t,i,s=0,r=t.length){if(!(s>=t.length)){s=(t.length+s)%t.length,r=r>=t.length?t.length:(t.length+r)%t.length;for(let e=s;e{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;const s=i(643);t.updateWindowsModeWrappedState=function(e){var t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),t=null==t?void 0:t.get(e.cols-1),e=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);e&&t&&(e.isWrapped=t[s.CHAR_DATA_CODE_INDEX]!==s.NULL_CELL_CODE&&t[s.CHAR_DATA_CODE_INDEX]!==s.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;t.AttributeData=class s{constructor(){this.fg=0,this.bg=0,this.extended=new i}static toColorRGB(e){return[e>>>16&255,e>>>8&255,255&e]}static fromColorRGB(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]}clone(){var e=new s;return e.fg=this.fg,e.bg=this.bg,e.extended=this.extended.clone(),e}isInverse(){return 67108864&this.fg}isBold(){return 134217728&this.fg}isUnderline(){return this.hasExtendedAttrs()&&0!==this.extended.underlineStyle?1:268435456&this.fg}isBlink(){return 536870912&this.fg}isInvisible(){return 1073741824&this.fg}isItalic(){return 67108864&this.bg}isDim(){return 134217728&this.bg}isStrikethrough(){return 2147483648&this.fg}isProtected(){return 536870912&this.bg}getFgColorMode(){return 50331648&this.fg}getBgColorMode(){return 50331648&this.bg}isFgRGB(){return 50331648==(50331648&this.fg)}isBgRGB(){return 50331648==(50331648&this.bg)}isFgPalette(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)}isBgPalette(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)}isFgDefault(){return 0==(50331648&this.fg)}isBgDefault(){return 0==(50331648&this.bg)}isAttributeDefault(){return 0===this.fg&&0===this.bg}getFgColor(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}}getBgColor(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}}hasExtendedAttrs(){return 268435456&this.bg}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()}isUnderlineColorRGB(){return 268435456&this.bg&&~this.extended.underlineColor?50331648==(50331648&this.extended.underlineColor):this.isFgRGB()}isUnderlineColorPalette(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()}isUnderlineColorDefault(){return 268435456&this.bg&&~this.extended.underlineColor?0==(50331648&this.extended.underlineColor):this.isFgDefault()}getUnderlineStyle(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0}};class i{constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}get ext(){return this._urlId?-469762049&this._ext|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(469762048&this._ext)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return 67108863&this._ext}set underlineColor(e){this._ext&=-67108864,this._ext|=67108863&e}get urlId(){return this._urlId}set urlId(e){this._urlId=e}clone(){return new i(this._ext,this._urlId)}isEmpty(){return 0===this.underlineStyle&&0===this._urlId}}t.ExtendedAttrs=i},9092:(e,i,t)=>{Object.defineProperty(i,"__esModule",{value:!0}),i.BufferStringIterator=i.Buffer=i.MAX_BUFFER_SIZE=void 0;const s=t(6349),p=t(8437),r=t(511),n=t(643),S=t(4634),o=t(4863),a=t(7116),h=t(3734);i.MAX_BUFFER_SIZE=4294967295,i.Buffer=class{constructor(e,t,i){this._hasScrollback=e,this._optionsService=t,this._bufferService=i,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.savedY=0,this.savedX=0,this.savedCurAttrData=p.DEFAULT_ATTR_DATA.clone(),this.savedCharset=a.DEFAULT_CHARSET,this.markers=[],this._nullCell=r.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]),this._whitespaceCell=r.CellData.fromCharData([0,n.WHITESPACE_CELL_CHAR,n.WHITESPACE_CELL_WIDTH,n.WHITESPACE_CELL_CODE]),this._isClearing=!1,this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}getNullCell(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new h.ExtendedAttrs),this._nullCell}getWhitespaceCell(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new h.ExtendedAttrs),this._whitespaceCell}getBlankLine(e,t){return new p.BufferLine(this._bufferService.cols,this.getNullCell(e),t)}get hasScrollback(){return this._hasScrollback&&this.lines.maxLength>this._rows}get isCursorInViewport(){var e=this.ybase+this.y-this.ydisp;return 0<=e&&ei.MAX_BUFFER_SIZE?i.MAX_BUFFER_SIZE:t:e}fillViewportRows(t){if(0===this.lines.length){void 0===t&&(t=p.DEFAULT_ATTR_DATA);let e=this._rows;for(;e--;)this.lines.push(this.getBlankLine(t))}}clear(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}resize(i,s){var r=this.getNullCell(p.DEFAULT_ATTR_DATA),e=this._getCorrectBufferLength(s);if(e>this.lines.maxLength&&(this.lines.maxLength=e),0s;e--)this.lines.length>s+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(ei))for(let e=0;ethis._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))}_reflowLarger(e,t){var i=(0,S.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(p.DEFAULT_ATTR_DATA));0=n&&de+r){for(let e=s.newLines.length-1;0<=e;e--)this.lines.set(t--,s.newLines[e]);t++,o.push({index:e+1,amount:s.newLines.length}),r+=s.newLines.length,s=l[++i]}else this.lines.set(t,a[e--]);let t=0;for(let e=o.length-1;0<=e;e--)o[e].index+=t,this.lines.onInsertEmitter.fire(o[e]),t+=o[e].amount;var n=Math.max(0,h+c-this.lines.maxLength);0=this._cols?this._cols-1:e<0?0:e}nextStop(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e=this._cols?this._cols-1:e<0?0:e}clearMarkers(t){this._isClearing=!0;for(let e=0;e{t.line-=e,t.line<0&&t.dispose()})),t.register(this.lines.onInsert(e=>{t.line>=e.index&&(t.line+=e.amount)})),t.register(this.lines.onDelete(e=>{t.line>=e.index&&t.linee.index&&(t.line-=e.amount)})),t.register(t.onDispose(()=>this._removeMarker(t))),t}_removeMarker(e){this._isClearing||this.markers.splice(this.markers.indexOf(e),1)}iterator(e,t,i,s,r){return new l(this,e,t,i,s,r)}};class l{constructor(e,t,i=0,s=e.lines.length,r=0,n=0){this._buffer=e,this._trimRight=t,this._startIndex=i,this._endIndex=s,this._startOverscan=r,this._endOverscan=n,this._startIndex<0&&(this._startIndex=0),this._endIndex>this._buffer.lines.length&&(this._endIndex=this._buffer.lines.length),this._current=this._startIndex}hasNext(){return this._currentthis._endIndex+this._endOverscan&&(t.last=this._endIndex+this._endOverscan),t.first=Math.max(t.first,0),t.last=Math.min(t.last,this._buffer.lines.length);let i="";for(let e=t.first;e<=t.last;++e)i+=this._buffer.translateBufferLineToString(e,this._trimRight);return this._current=t.last+1,{range:t,content:i}}}i.BufferStringIterator=l},8437:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;const r=i(482),n=i(643),o=i(511),a=i(3734),s=(t.DEFAULT_ATTR_DATA=Object.freeze(new a.AttributeData),{startIndex:0});t.BufferLine=class h{constructor(t,e,i=!1){this.isWrapped=i,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*t);var s=e||o.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]);for(let e=0;e>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):i]}set(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],1>22}hasWidth(e){return 12582912&this._data[3*e+0]}getFg(e){return this._data[3*e+1]}getBg(e){return this._data[3*e+2]}hasContent(e){return 4194303&this._data[3*e+0]}getCodePoint(e){var t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t}isCombined(e){return 2097152&this._data[3*e+0]}getString(e){var t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,r.stringFromCodePoint)(2097151&t):""}isProtected(e){return 536870912&this._data[3*e+2]}loadCell(e,t){return s.startIndex=3*e,t.content=this._data[s.startIndex+0],t.fg=this._data[s.startIndex+1],t.bg=this._data[s.startIndex+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t}setCell(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg}setCellFromCodePoint(e,t,i,s,r,n){268435456&r&&(this._extendedAttrs[e]=n),this._data[3*e+0]=t|i<<22,this._data[3*e+1]=s,this._data[3*e+2]=r}addCodepointToCell(e,t){let i=this._data[3*e+0];2097152&i?this._combined[e]+=(0,r.stringFromCodePoint)(t):(i=2097151&i?(this._combined[e]=(0,r.stringFromCodePoint)(2097151&i)+(0,r.stringFromCodePoint)(t),-2097152&i|2097152):t|1<<22,this._data[3*e+0]=i)}insertCells(t,i,s,r){if((t%=this.length)&&2===this.getWidth(t-1)&&this.setCellFromCodePoint(t-1,0,1,(null==r?void 0:r.fg)||0,(null==r?void 0:r.bg)||0,(null==r?void 0:r.extended)||new a.ExtendedAttrs),ithis.length){var e=new Uint32Array(3*t);this.length&&(3*t>22);return 0}copyCellsFrom(i,s,r,e,t){var n=i._data;if(t)for(let t=e-1;0<=t;t--){for(let e=0;e<3;e++)this._data[3*(r+t)+e]=n[3*(s+t)+e];268435456&n[3*(s+t)+2]&&(this._extendedAttrs[r+t]=i._extendedAttrs[s+t])}else for(let t=0;t=s&&(this._combined[t-s+r]=i._combined[t])}}translateToString(e=!1,t=0,i=this.length){e&&(i=Math.min(i,this.getTrimmedLength()));let s="";for(;t>22||1}return s}}},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error(`Buffer range end (${e.end.x}, ${e.end.y}) cannot be before start (${e.start.x}, ${e.start.y})`);return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function f(e,t,i){var s;return t===e.length-1?e[t].getTrimmedLength():(s=!e[t].hasContent(i-1)&&1===e[t].getWidth(i-1),e=2===e[t+1].getWidth(0),s&&e?i-1:i)}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(o,a,h,l,c){const _=[];for(let n=0;n=n&&lt||0===d[e].getTrimmedLength());e--)r++;0f(i,t,s)).reduce((e,t)=>e+t);let n=0,o=0,a=0;for(;ah&&(n-=h,o++),2===i[o].getWidth(n-1)),h=(h&&n--,h?e-1:e);t.push(h),a+=h}return t},t.getWrappedLineTrimmedLength=f},5295:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;const s=i(9092),r=i(8460),n=i(844);class o extends n.Disposable{constructor(e,t){super(),this._optionsService=e,this._bufferService=t,this._onBufferActivate=this.register(new r.EventEmitter),this.reset()}get onBufferActivate(){return this._onBufferActivate.event}reset(){this._normal=new s.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new s.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()}get alt(){return this._alt}get active(){return this._activeBuffer}get normal(){return this._normal}activateNormalBuffer(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clearAllMarkers(),this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))}activateAltBuffer(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))}resize(e,t){this._normal.resize(e,t),this._alt.resize(e,t)}setupTabStops(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)}}t.BufferSet=o},511:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;const s=i(482),r=i(643),n=i(3734);class o extends n.AttributeData{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new n.ExtendedAttrs,this.combinedData=""}static fromCharData(e){var t=new o;return t.setFromCharData(e),t}isCombined(){return 2097152&this.content}getWidth(){return this.content>>22}getChars(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,s.stringFromCodePoint)(2097151&this.content):""}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content}setFromCharData(e){this.fg=e[r.CHAR_DATA_ATTR_INDEX],this.bg=0;let t=!1;var i,s;2{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_EXT=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=256,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.DEFAULT_EXT=0,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this.line=e,this._id=n._nextId++,this.isDisposed=!1,this._onDispose=new s.EventEmitter}get id(){return this._id}get onDispose(){return this._onDispose.event}dispose(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),super.dispose())}}(t.Marker=n)._nextId=1},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"},t.CHARSETS.A={"#":"£"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"£","@":"¾","[":"ij","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS.R={"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"},t.CHARSETS.Y={"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"},t.CHARSETS.Z={"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS["="]={"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}},2584:(e,t)=>{var i,s;Object.defineProperty(t,"__esModule",{value:!0}),t.C1_ESCAPED=t.C1=t.C0=void 0,(s=i=t.C0||(t.C0={})).NUL="\0",s.SOH="",s.STX="",s.ETX="",s.EOT="",s.ENQ="",s.ACK="",s.BEL="",s.BS="\b",s.HT="\t",s.LF="\n",s.VT="\v",s.FF="\f",s.CR="\r",s.SO="",s.SI="",s.DLE="",s.DC1="",s.DC2="",s.DC3="",s.DC4="",s.NAK="",s.SYN="",s.ETB="",s.CAN="",s.EM="",s.SUB="",s.ESC="",s.FS="",s.GS="",s.RS="",s.US="",s.SP=" ",s.DEL="",(s=t.C1||(t.C1={})).PAD="€",s.HOP="",s.BPH="‚",s.NBH="ƒ",s.IND="„",s.NEL="…",s.SSA="†",s.ESA="‡",s.HTS="ˆ",s.HTJ="‰",s.VTS="Š",s.PLD="‹",s.PLU="Œ",s.RI="",s.SS2="Ž",s.SS3="",s.DCS="",s.PU1="‘",s.PU2="’",s.STS="“",s.CCH="”",s.MW="•",s.SPA="–",s.EPA="—",s.SOS="˜",s.SGCI="™",s.SCI="š",s.CSI="›",s.ST="œ",s.OSC="",s.PM="ž",s.APC="Ÿ",(t.C1_ESCAPED||(t.C1_ESCAPED={})).ST=i.ESC+"\\"},7399:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;const o=i(2584),a={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(t,i,e,s){var r={type:0,cancel:!1,key:void 0},n=(t.shiftKey?1:0)|(t.altKey?2:0)|(t.ctrlKey?4:0)|(t.metaKey?8:0);switch(t.keyCode){case 0:"UIKeyInputUpArrow"===t.key?r.key=i?o.C0.ESC+"OA":o.C0.ESC+"[A":"UIKeyInputLeftArrow"===t.key?r.key=i?o.C0.ESC+"OD":o.C0.ESC+"[D":"UIKeyInputRightArrow"===t.key?r.key=i?o.C0.ESC+"OC":o.C0.ESC+"[C":"UIKeyInputDownArrow"===t.key&&(r.key=i?o.C0.ESC+"OB":o.C0.ESC+"[B");break;case 8:t.altKey?r.key=o.C0.ESC+o.C0.DEL:r.key=o.C0.DEL;break;case 9:t.shiftKey?r.key=o.C0.ESC+"[Z":(r.key=o.C0.HT,r.cancel=!0);break;case 13:r.key=t.altKey?o.C0.ESC+o.C0.CR:o.C0.CR,r.cancel=!0;break;case 27:r.key=o.C0.ESC,t.altKey&&(r.key=o.C0.ESC+o.C0.ESC),r.cancel=!0;break;case 37:t.metaKey||(n?(r.key=o.C0.ESC+"[1;"+(1+n)+"D",r.key===o.C0.ESC+"[1;3D"&&(r.key=o.C0.ESC+(e?"b":"[1;5D"))):r.key=i?o.C0.ESC+"OD":o.C0.ESC+"[D");break;case 39:t.metaKey||(n?(r.key=o.C0.ESC+"[1;"+(1+n)+"C",r.key===o.C0.ESC+"[1;3C"&&(r.key=o.C0.ESC+(e?"f":"[1;5C"))):r.key=i?o.C0.ESC+"OC":o.C0.ESC+"[C");break;case 38:t.metaKey||(n?(r.key=o.C0.ESC+"[1;"+(1+n)+"A",e||r.key!==o.C0.ESC+"[1;3A"||(r.key=o.C0.ESC+"[1;5A")):r.key=i?o.C0.ESC+"OA":o.C0.ESC+"[A");break;case 40:t.metaKey||(n?(r.key=o.C0.ESC+"[1;"+(1+n)+"B",e||r.key!==o.C0.ESC+"[1;3B"||(r.key=o.C0.ESC+"[1;5B")):r.key=i?o.C0.ESC+"OB":o.C0.ESC+"[B");break;case 45:t.shiftKey||t.ctrlKey||(r.key=o.C0.ESC+"[2~");break;case 46:r.key=n?o.C0.ESC+"[3;"+(1+n)+"~":o.C0.ESC+"[3~";break;case 36:r.key=n?o.C0.ESC+"[1;"+(1+n)+"H":i?o.C0.ESC+"OH":o.C0.ESC+"[H";break;case 35:r.key=n?o.C0.ESC+"[1;"+(1+n)+"F":i?o.C0.ESC+"OF":o.C0.ESC+"[F";break;case 33:t.shiftKey?r.type=2:t.ctrlKey?r.key=o.C0.ESC+"[5;"+(1+n)+"~":r.key=o.C0.ESC+"[5~";break;case 34:t.shiftKey?r.type=3:t.ctrlKey?r.key=o.C0.ESC+"[6;"+(1+n)+"~":r.key=o.C0.ESC+"[6~";break;case 112:r.key=n?o.C0.ESC+"[1;"+(1+n)+"P":o.C0.ESC+"OP";break;case 113:r.key=n?o.C0.ESC+"[1;"+(1+n)+"Q":o.C0.ESC+"OQ";break;case 114:r.key=n?o.C0.ESC+"[1;"+(1+n)+"R":o.C0.ESC+"OR";break;case 115:r.key=n?o.C0.ESC+"[1;"+(1+n)+"S":o.C0.ESC+"OS";break;case 116:r.key=n?o.C0.ESC+"[15;"+(1+n)+"~":o.C0.ESC+"[15~";break;case 117:r.key=n?o.C0.ESC+"[17;"+(1+n)+"~":o.C0.ESC+"[17~";break;case 118:r.key=n?o.C0.ESC+"[18;"+(1+n)+"~":o.C0.ESC+"[18~";break;case 119:r.key=n?o.C0.ESC+"[19;"+(1+n)+"~":o.C0.ESC+"[19~";break;case 120:r.key=n?o.C0.ESC+"[20;"+(1+n)+"~":o.C0.ESC+"[20~";break;case 121:r.key=n?o.C0.ESC+"[21;"+(1+n)+"~":o.C0.ESC+"[21~";break;case 122:r.key=n?o.C0.ESC+"[23;"+(1+n)+"~":o.C0.ESC+"[23~";break;case 123:r.key=n?o.C0.ESC+"[24;"+(1+n)+"~":o.C0.ESC+"[24~";break;default:if(!t.ctrlKey||t.shiftKey||t.altKey||t.metaKey)if(e&&!s||!t.altKey||t.metaKey)!e||t.altKey||t.ctrlKey||t.shiftKey||!t.metaKey?t.key&&!t.ctrlKey&&!t.altKey&&!t.metaKey&&48<=t.keyCode&&1===t.key.length?r.key=t.key:t.key&&t.ctrlKey&&("_"===t.key&&(r.key=o.C0.US),"@"===t.key)&&(r.key=o.C0.NUL):65===t.keyCode&&(r.type=1);else{const i=a[t.keyCode],e=null==i?void 0:i[t.shiftKey?1:0];if(e)r.key=o.C0.ESC+e;else if(65<=t.keyCode&&t.keyCode<=90){const i=t.ctrlKey?t.keyCode-64:t.keyCode+32;let e=String.fromCharCode(i);t.shiftKey&&(e=e.toUpperCase()),r.key=o.C0.ESC+e}else if("Dead"===t.key&&t.code.startsWith("Key")){let e=t.code.slice(3,4);t.shiftKey||(e=e.toLowerCase()),r.key=o.C0.ESC+e,r.cancel=!0}}else 65<=t.keyCode&&t.keyCode<=90?r.key=String.fromCharCode(t.keyCode-64):32===t.keyCode?r.key=o.C0.NUL:51<=t.keyCode&&t.keyCode<=55?r.key=String.fromCharCode(t.keyCode-51+27):56===t.keyCode?r.key=o.C0.DEL:219===t.keyCode?r.key=o.C0.ESC:220===t.keyCode?r.key=o.C0.FS:221===t.keyCode&&(r.key=o.C0.GS)}return r}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return 65535>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(i,e=0,s=i.length){let r="";for(let t=e;t>10))+String.fromCharCode(e%1024+56320)):r+=String.fromCharCode(e)}return r},t.StringToUtf32=class{constructor(){this._interim=0}clear(){this._interim=0}decode(t,i){const s=t.length;if(!s)return 0;let r=0,n=0;if(this._interim){const s=t.charCodeAt(n++);56320<=s&&s<=57343?i[r++]=1024*(this._interim-55296)+s-56320+65536:(i[r++]=this._interim,i[r++]=s),this._interim=0}for(let e=n;e=s)return this._interim=n,r;var o=t.charCodeAt(e);56320<=o&&o<=57343?i[r++]=1024*(n-55296)+o-56320+65536:(i[r++]=n,i[r++]=o)}else 65279!==n&&(i[r++]=n)}return r}},t.Utf8ToUtf32=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(r,n){var o=r.length;if(!o)return 0;let e,t,i,s,a=0,h=0,l=0;if(this.interim[0]){let e=!1,t=this.interim[0];t&=192==(224&t)?31:224==(240&t)?15:7;let i,s=0;for(;(i=63&this.interim[++s])&&s<4;)t=(t<<=6)|i;const h=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,c=h-s;for(;l=o)return 0;if(128!=(192&(i=r[l++]))){l--,e=!0;break}this.interim[s++]=i,t=(t<<=6)|63&i}e||(2==h?t<128?l--:n[a++]=t:3==h?t<2048||55296<=t&&t<=57343||65279===t||(n[a++]=t):t<65536||1114111=o)return this.interim[0]=e,a;128!=(192&(t=r[_++]))?_--:(h=(31&e)<<6|63&t)<128?_--:n[a++]=h}else if(224==(240&e)){if(_>=o)return this.interim[0]=e,a;if(128!=(192&(t=r[_++])))_--;else{if(_>=o)return this.interim[0]=e,this.interim[1]=t,a;128!=(192&(i=r[_++]))?_--:(h=(15&e)<<12|(63&t)<<6|63&i)<2048||55296<=h&&h<=57343||65279===h||(n[a++]=h)}}else if(240==(248&e)){if(_>=o)return this.interim[0]=e,a;if(128!=(192&(t=r[_++])))_--;else{if(_>=o)return this.interim[0]=e,this.interim[1]=t,a;if(128!=(192&(i=r[_++])))_--;else{if(_>=o)return this.interim[0]=e,this.interim[1]=t,this.interim[2]=i,a;128!=(192&(s=r[_++]))?_--:(h=(7&e)<<18|(63&t)<<12|(63&i)<<6|63&s)<65536||1114111{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;const s=i(8273),r=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],n=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]];let o;t.UnicodeV6=class{constructor(){if(this.version="6",!o){o=new Uint8Array(65536),(0,s.fill)(o,1),(o[0]=0,s.fill)(o,0,1,32),(0,s.fill)(o,0,127,160),(0,s.fill)(o,2,4352,4448),o[9001]=2,o[9002]=2,(0,s.fill)(o,2,11904,42192),o[12351]=1,(0,s.fill)(o,2,44032,55204),(0,s.fill)(o,2,63744,64256),(0,s.fill)(o,2,65040,65050),(0,s.fill)(o,2,65072,65136),(0,s.fill)(o,2,65280,65377),(0,s.fill)(o,2,65504,65511);for(let e=0;et[r][1]))for(;r>=s;)if(e>t[i=s+r>>1][1])s=1+i;else{if(!(e{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;const s=i(8460),n="undefined"==typeof queueMicrotask?e=>{Promise.resolve().then(e)}:queueMicrotask;t.WriteBuffer=class{constructor(e){this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0,this._onWriteParsed=new s.EventEmitter}get onWriteParsed(){return this._onWriteParsed.event}writeSync(e,t){if(void 0!==t&&this._syncCalls>t)this._syncCalls=0;else if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,!this._isSyncWriting){var i;for(this._isSyncWriting=!0;i=this._writeBuffer.shift();){this._action(i);const e=this._callbacks.shift();e&&e()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}}write(e,t){if(5e7this._innerWrite())),this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)}_innerWrite(e=0,t=!0){const i=e||Date.now();for(;this._writeBuffer.length>this._bufferOffset;){const e=this._writeBuffer[this._bufferOffset],r=this._action(e,t);if(r){const e=e=>12<=Date.now()-i?setTimeout(()=>this._innerWrite(0,e)):this._innerWrite(i,e);return void r.catch(e=>(n(()=>{throw e}),Promise.resolve(!1))).then(e)}var s=this._callbacks[this._bufferOffset];if(s&&s(),this._bufferOffset++,this._pendingData-=e.length,12<=Date.now()-i)break}this._writeBuffer.length>this._bufferOffset?(50this._innerWrite())):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0),this._onWriteParsed.fire()}}},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;const r=/^([\da-f])\/([\da-f])\/([\da-f])$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,n=/^[\da-f]+$/;function o(e,t){var i=e.toString(16),s=i.length<2?"0"+i:i;switch(t){case 4:return i[0];case 8:return s;case 12:return(s+s).slice(0,3);default:return s+s}}t.parseColor=function(i){if(i){let t=i.toLowerCase();if(0===t.indexOf("rgb:")){t=t.slice(4);const i=r.exec(t);if(i){const e=i[1]?15:i[4]?255:i[7]?4095:65535;return[Math.round(parseInt(i[1]||i[4]||i[7]||i[10],16)/e*255),Math.round(parseInt(i[2]||i[5]||i[8]||i[11],16)/e*255),Math.round(parseInt(i[3]||i[6]||i[9]||i[12],16)/e*255)]}}else if(0===t.indexOf("#")&&(t=t.slice(1),n.exec(t))&&[3,6,9,12].includes(t.length)){const i=t.length/3,r=[0,0,0];for(let e=0;e<3;++e){var s=parseInt(t.slice(i*e,i*e+i),16);r[e]=1==i?s<<4:2==i?s:3==i?s>>4:s>>8}return r}}},t.toRgbString=function(e,t=16){var[e,i,s]=e;return`rgb:${o(e,t)}/${o(i,t)}/`+o(s,t)}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;const r=i(482),s=i(8742),n=i(5770),o=[],a=(t.DcsParser=class{constructor(){this._handlers=Object.create(null),this._active=o,this._ident=0,this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=o}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}reset(){if(this._active.length)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;0<=e;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=o,this._ident=0}hook(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||o,this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].hook(t);else this._handlerFb(this._ident,"HOOK",t)}put(t,i,s){if(this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].put(t,i,s);else this._handlerFb(this._ident,"PUT",(0,r.utf32ToString)(t,i,s))}unhook(s,r=!0){if(this._active.length){let e=!1,t=this._active.length-1,i=!1;if(this._stack.paused&&(t=this._stack.loopPosition-1,e=r,i=this._stack.fallThrough,this._stack.paused=!1),!i&&!1===e){for(;0<=t&&!0!==(e=this._active[t].unhook(s));t--)if(e instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=t,this._stack.fallThrough=!1,e;t--}for(;0<=t;t--)if((e=this._active[t].unhook(!1))instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=t,this._stack.fallThrough=!0,e}else this._handlerFb(this._ident,"UNHOOK",s);this._active=o,this._ident=0}},new s.Params);a.addParam(0),t.DcsHandler=class{constructor(e){this._handler=e,this._data="",this._params=a,this._hitLimit=!1}hook(e){this._params=1n.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}unhook(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data,this._params))instanceof Promise)return t.then(e=>(this._params=a,this._data="",this._hitLimit=!1,e));return this._params=a,this._data="",this._hitLimit=!1,t}}},2015:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;const s=i(844),r=i(8273),n=i(8742),o=i(6242),a=i(6351);class h{constructor(e){this.table=new Uint8Array(e)}setDefault(e,t){(0,r.fill)(this.table,e<<4|t)}add(e,t,i,s){this.table[t<<8|e]=i<<4|s}addMany(t,i,s,r){for(let e=0;et),t=(e,t)=>i.slice(e,t),s=t(32,127),r=t(0,24);r.push(25),r.push.apply(r,t(28,32));var n=t(0,14);let o;for(o in e.setDefault(1,0),e.addMany(s,0,2,0),n)e.addMany([24,26,153,154],o,3,0),e.addMany(t(128,144),o,3,0),e.addMany(t(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(r,0,3,0),e.addMany(r,1,3,1),e.add(127,1,0,1),e.addMany(r,8,0,8),e.addMany(r,3,3,3),e.add(127,3,0,3),e.addMany(r,4,3,4),e.add(127,4,0,4),e.addMany(r,6,3,6),e.addMany(r,5,3,5),e.add(127,5,0,5),e.addMany(r,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(s,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(t(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(s,7,0,7),e.addMany(r,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(t(64,127),3,7,0),e.addMany(t(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(t(48,60),4,8,4),e.addMany(t(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(t(32,64),6,0,6),e.add(127,6,0,6),e.addMany(t(64,127),6,0,0),e.addMany(t(32,48),3,9,5),e.addMany(t(32,48),5,9,5),e.addMany(t(48,64),5,0,6),e.addMany(t(64,127),5,7,0),e.addMany(t(32,48),4,9,5),e.addMany(t(32,48),1,9,2),e.addMany(t(32,48),2,9,2),e.addMany(t(48,127),2,10,0),e.addMany(t(48,80),1,10,0),e.addMany(t(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(t(96,127),1,10,0),e.add(80,1,11,9),e.addMany(r,9,0,9),e.add(127,9,0,9),e.addMany(t(28,32),9,0,9),e.addMany(t(32,48),9,9,12),e.addMany(t(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(r,11,0,11),e.addMany(t(32,128),11,0,11),e.addMany(t(28,32),11,0,11),e.addMany(r,10,0,10),e.add(127,10,0,10),e.addMany(t(28,32),10,0,10),e.addMany(t(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(t(32,48),10,9,12),e.addMany(r,12,0,12),e.add(127,12,0,12),e.addMany(t(28,32),12,0,12),e.addMany(t(32,48),12,9,12),e.addMany(t(48,64),12,0,11),e.addMany(t(64,127),12,12,13),e.addMany(t(64,127),10,12,13),e.addMany(t(64,127),9,12,13),e.addMany(r,13,13,13),e.addMany(s,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(c,0,2,0),e.add(c,8,5,8),e.add(c,6,0,6),e.add(c,11,0,11),e.add(c,13,13,13),e}();class l extends s.Disposable{constructor(e=t.VT500_TRANSITION_TABLE){super(),this._transitions=e,this._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},this.initialState=0,this.currentState=this.initialState,this._params=new n.Params,this._params.addParam(0),this._collect=0,this.precedingCodepoint=0,this._printHandlerFb=(e,t,i)=>{},this._executeHandlerFb=e=>{},this._csiHandlerFb=(e,t)=>{},this._escHandlerFb=e=>{},this._errorHandlerFb=e=>e,this._printHandler=this._printHandlerFb,this._executeHandlers=Object.create(null),this._csiHandlers=Object.create(null),this._escHandlers=Object.create(null),this._oscParser=new o.OscParser,this._dcsParser=new a.DcsParser,this._errorHandler=this._errorHandlerFb,this.registerEscHandler({final:"\\"},()=>!0)}_identifier(t,e=[64,126]){let i=0;if(t.prefix){if(1s||s>e[1])throw new Error(`final must be in range ${e[0]} .. `+e[1]);return i=(i<<=8)|s}identToString(e){for(var t=[];e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")}dispose(){this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null),this._oscParser.dispose(),this._dcsParser.dispose()}setPrintHandler(e){this._printHandler=e}clearPrintHandler(){this._printHandler=this._printHandlerFb}registerEscHandler(e,t){e=this._identifier(e,[48,126]);void 0===this._escHandlers[e]&&(this._escHandlers[e]=[]);const i=this._escHandlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearEscHandler(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]}setEscHandlerFallback(e){this._escHandlerFb=e}setExecuteHandler(e,t){this._executeHandlers[e.charCodeAt(0)]=t}clearExecuteHandler(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]}setExecuteHandlerFallback(e){this._executeHandlerFb=e}registerCsiHandler(e,t){e=this._identifier(e);void 0===this._csiHandlers[e]&&(this._csiHandlers[e]=[]);const i=this._csiHandlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearCsiHandler(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]}setCsiHandlerFallback(e){this._csiHandlerFb=e}registerDcsHandler(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)}clearDcsHandler(e){this._dcsParser.clearHandler(this._identifier(e))}setDcsHandlerFallback(e){this._dcsParser.setHandlerFallback(e)}registerOscHandler(e,t){return this._oscParser.registerHandler(e,t)}clearOscHandler(e){this._oscParser.clearHandler(e)}setOscHandlerFallback(e){this._oscParser.setHandlerFallback(e)}setErrorHandler(e){this._errorHandler=e}clearErrorHandler(){this._errorHandler=this._errorHandlerFb}reset(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,(this.precedingCodepoint=0)!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])}_preserveStack(e,t,i,s,r){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=i,this._parseStack.transition=s,this._parseStack.chunkPos=r}parse(s,r,t){let n,o=0,a=0,h=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,h=this._parseStack.chunkPos+1;else{if(void 0===t||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");const r=this._parseStack.handlers;let e=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===t&&-1>4){case 2:for(let e=i+1;;++e){if(e>=r||(o=s[e])<32||126=r||(o=s[e])<32||126=r||(o=s[e])<32||126=r||(o=s[e])<32||126=r||24===(o=s[e])||26===o||27===o||127=r||(o=s[e])<32||127{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;const s=i(5770),r=i(482),n=[];t.OscParser=class{constructor(){this._state=0,this._active=n,this._id=-1,this._handlers=Object.create(null),this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=n}reset(){if(2===this._state)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;0<=e;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=n,this._id=-1,this._state=0}_start(){if(this._active=this._handlers[this._id]||n,this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].start();else this._handlerFb(this._id,"START")}_put(t,i,s){if(this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].put(t,i,s);else this._handlerFb(this._id,"PUT",(0,r.utf32ToString)(t,i,s))}start(){this.reset(),this._state=1}put(e,t,i){if(3!==this._state){if(1===this._state)for(;ts.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}end(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data))instanceof Promise)return t.then(e=>(this._data="",this._hitLimit=!1,e));return this._data="",this._hitLimit=!1,t}}},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;const r=2147483647;class s{constructor(e=32,t=32){if(this.maxLength=e,256<(this.maxSubParamsLength=t))throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}static fromArray(t){var i=new s;if(t.length)for(let e=Array.isArray(t[0])?1:0;e>8,s=255&this._subParamsIdx[e];0=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>r?r:e}}addSubParam(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>r?r:e,this._subParamsIdx[this.length-1]++}}hasSubParams(e){return 0<(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)}getSubParams(e){var t=this._subParamsIdx[e]>>8,e=255&this._subParamsIdx[e];return 0>8,s=255&this._subParamsIdx[e];0{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0,t.AddonManager=class{constructor(){this._addons=[]}dispose(){for(let e=this._addons.length-1;0<=e;e--)this._addons[e].instance.dispose()}loadAddon(e,t){const i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=()=>this._wrappedAddonDispose(i),t.activate(e)}_wrappedAddonDispose(i){if(!i.isDisposed){let t=-1;for(let e=0;e{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;const s=i(3785),r=i(511);t.BufferApiView=class{constructor(e,t){this._buffer=e,this.type=t}init(e){return this._buffer=e,this}get cursorY(){return this._buffer.y}get cursorX(){return this._buffer.x}get viewportY(){return this._buffer.ydisp}get baseY(){return this._buffer.ybase}get length(){return this._buffer.lines.length}getLine(e){e=this._buffer.lines.get(e);if(e)return new s.BufferLineApiView(e)}getNullCell(){return new r.CellData}}},3785:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;const s=i(511);t.BufferLineApiView=class{constructor(e){this._line=e}get isWrapped(){return this._line.isWrapped}get length(){return this._line.length}getCell(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new s.CellData)}translateToString(e,t,i){return this._line.translateToString(e,t,i)}}},8285:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;const s=i(8771),r=i(8460);t.BufferNamespaceApi=class{constructor(e){this._core=e,this._onBufferChange=new r.EventEmitter,this._normal=new s.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new s.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate(()=>this._onBufferChange.fire(this.active))}get onBufferChange(){return this._onBufferChange.event}get active(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")}get normal(){return this._normal.init(this._core.buffers.normal)}get alternate(){return this._alternate.init(this._core.buffers.alt)}}},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0,t.ParserApi=class{constructor(e){this._core=e}registerCsiHandler(e,t){return this._core.registerCsiHandler(e,e=>t(e.toArray()))}addCsiHandler(e,t){return this.registerCsiHandler(e,t)}registerDcsHandler(e,i){return this._core.registerDcsHandler(e,(e,t)=>i(e,t.toArray()))}addDcsHandler(e,t){return this.registerDcsHandler(e,t)}registerEscHandler(e,t){return this._core.registerEscHandler(e,t)}addEscHandler(e,t){return this.registerEscHandler(e,t)}registerOscHandler(e,t){return this._core.registerOscHandler(e,t)}addOscHandler(e,t){return this.registerOscHandler(e,t)}}},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0,t.UnicodeApi=class{constructor(e){this._core=e}register(e){this._core.unicodeService.register(e)}get versions(){return this._core.unicodeService.versions}get activeVersion(){return this._core.unicodeService.activeVersion}set activeVersion(e){this._core.unicodeService.activeVersion=e}}},744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3=s.ybase&&(this.isUserScrolling=!1);var r=s.ydisp;s.ydisp=Math.max(Math.min(s.ydisp+e,s.ybase),0),r===s.ydisp||t||this._onScroll.fire(s.ydisp)}scrollPages(e){this.scrollLines(e*(this.rows-1))}scrollToTop(){this.scrollLines(-this.buffer.ydisp)}scrollToBottom(){this.scrollLines(this.buffer.ybase-this.buffer.ydisp)}scrollToLine(e){e-=this.buffer.ydisp;0!=e&&this.scrollLines(e)}},i=s([r(0,n.IOptionsService)],i);t.BufferService=i},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0,t.CharsetService=class{constructor(){this.glevel=0,this._charsets=[]}reset(){this.charset=void 0,this._charsets=[],this.glevel=0}setgLevel(e){this.glevel=e,this.charset=this._charsets[e]}setgCharset(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)}}},1753:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3!1},X10:{events:1,restrict:e=>4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,!(e.shift=!1))},VT200:{events:19,restrict:e=>32!==e.action},DRAG:{events:23,restrict:e=>32!==e.action||3!==e.button},ANY:{events:31,restrict:e=>!0}};function h(e,t){let i=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?i=(i|=64)|e.action:(i|=3&e.button,4&e.button&&(i|=64),8&e.button&&(i|=128),32===e.action?i|=32:0!==e.action||t||(i|=3)),i}const l=String.fromCharCode,c={DEFAULT:e=>{e=[h(e,!1)+32,e.col+32,e.row+32];return 255{var t=0===e.action&&4!==e.button?"m":"M";return`[<${h(e,!0)};${e.col};`+e.row+t},SGR_PIXELS:e=>{var t=0===e.action&&4!==e.button?"m":"M";return`[<${h(e,!0)};${e.x};`+e.y+t}};i=class{constructor(e,t){this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._onProtocolChange=new o.EventEmitter,this._lastEvent=null;for(const e of Object.keys(a))this.addProtocol(e,a[e]);for(const e of Object.keys(c))this.addEncoding(e,c[e]);this.reset()}addProtocol(e,t){this._protocols[e]=t}addEncoding(e,t){this._encodings[e]=t}get activeProtocol(){return this._activeProtocol}get areMouseEventsActive(){return 0!==this._protocols[this._activeProtocol].events}set activeProtocol(e){if(!this._protocols[e])throw new Error(`unknown protocol "${e}"`);this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)}get activeEncoding(){return this._activeEncoding}set activeEncoding(e){if(!this._encodings[e])throw new Error(`unknown encoding "${e}"`);this._activeEncoding=e}reset(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null}get onProtocolChange(){return this._onProtocolChange.event}triggerMouseEvent(e){var t;return!(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows||4===e.button&&32===e.action||3===e.button&&32!==e.action||4!==e.button&&(2===e.action||3===e.action)||(e.col++,e.row++,32===e.action&&this._lastEvent&&this._equalEvents(this._lastEvent,e,"SGR_PIXELS"===this._activeEncoding))||!this._protocols[this._activeProtocol].restrict(e)||((t=this._encodings[this._activeEncoding](e))&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,0))}explainEvents(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}}_equalEvents(e,t,i){if(i){if(e.x!==t.x)return!1;if(e.y!==t.y)return!1}else{if(e.col!==t.col)return!1;if(e.row!==t.row)return!1}return e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift}},i=s([r(0,n.IBufferService),r(1,n.ICoreService)],i);t.CoreMouseService=i},6975:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._scrollToBottom=void 0}),this.modes=(0,a.clone)(l),this.decPrivateModes=(0,a.clone)(c)}get onData(){return this._onData.event}get onUserInput(){return this._onUserInput.event}get onBinary(){return this._onBinary.event}reset(){this.modes=(0,a.clone)(l),this.decPrivateModes=(0,a.clone)(c)}triggerDataEvent(e,t=!1){var i;this._optionsService.rawOptions.disableStdin||((i=this._bufferService.buffer).ybase!==i.ydisp&&this._scrollToBottom(),t&&this._onUserInput.fire(),this._logService.debug(`sending data "${e}"`,()=>e.split("").map(e=>e.charCodeAt(0))),this._onData.fire(e))}triggerBinaryEvent(e){this._optionsService.rawOptions.disableStdin||(this._logService.debug(`sending binary "${e}"`,()=>e.split("").map(e=>e.charCodeAt(0))),this._onBinary.fire(e))}},i=s([r(1,n.IBufferService),r(2,n.ILogService),r(3,n.IOptionsService)],i);t.CoreService=i},9074:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DecorationService=void 0;const s=i(8055),r=i(8460),n=i(844),o=i(6106),a={xmin:0,xmax:0};class h extends n.Disposable{constructor(){super(...arguments),this._decorations=new o.SortedList(e=>null==e?void 0:e.marker.line),this._onDecorationRegistered=this.register(new r.EventEmitter),this._onDecorationRemoved=this.register(new r.EventEmitter)}get onDecorationRegistered(){return this._onDecorationRegistered.event}get onDecorationRemoved(){return this._onDecorationRemoved.event}get decorations(){return this._decorations.values()}registerDecoration(e){if(!e.marker.isDisposed){const t=new l(e);if(t){const e=t.marker.onDispose(()=>t.dispose());t.onDispose(()=>{t&&(this._decorations.delete(t)&&this._onDecorationRemoved.fire(t),e.dispose())}),this._decorations.insert(t),this._onDecorationRegistered.fire(t)}return t}}reset(){for(const e of this._decorations.values())e.dispose();this._decorations.clear()}*getDecorationsAtCell(e,t,i){var s,r;for(const n of this._decorations.getKeyIterator(t))s=null!=(s=n.options.x)?s:0,r=s+(null!=(r=n.options.width)?r:1),s<=e&&e{var t;a.xmin=null!=(t=e.options.x)?t:0,a.xmax=a.xmin+(null!=(t=e.options.width)?t:1),i>=a.xmin&&ithis._end&&(this._end=e)}markRangeDirty(e,t){var i;tthis._end&&(this._end=t)}markAllDirty(){this.markRangeDirty(0,this._bufferService.rows-1)}},n=s([r(0,i.IBufferService)],n);t.DirtyRowService=n},4348:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;const s=i(2585),n=i(8343);class r{constructor(...e){this._entries=new Map;for(var[t,i]of e)this.set(t,i)}set(e,t){var i=this._entries.get(e);return this._entries.set(e,t),i}forEach(i){this._entries.forEach((e,t)=>i(t,e))}has(e){return this._entries.has(e)}get(e){return this._entries.get(e)}}t.ServiceCollection=r,t.InstantiationService=class{constructor(){this._services=new r,this._services.set(s.IInstantiationService,this)}setService(e,t){this._services.set(e,t)}getService(e){return this._services.get(e)}createInstance(e,...t){const i=(0,n.getServiceDependencies)(e).sort((e,t)=>e.index-t.index),s=[];for(const t of i){const i=this._services.get(t.id);if(!i)throw new Error(`[createInstance] ${e.name} depends on UNKNOWN service ${t.id}.`);s.push(i)}var r=0{"logLevel"===e&&this._updateLogLevel()})}_updateLogLevel(){this.logLevel=o[this._optionsService.rawOptions.logLevel]}_evalLazyOptionalParams(t){for(let e=0;e{Object.defineProperty(s,"__esModule",{value:!0}),s.OptionsService=s.DEFAULT_OPTIONS=void 0;const i=t(8460),r=t(6114),n=(s.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,customGlyphs:!0,drawBoldTextInBrightColors:!0,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",lineHeight:1,letterSpacing:0,linkHandler:null,logLevel:"info",scrollback:1e3,scrollSensitivity:1,screenReaderMode:!1,smoothScrollDuration:0,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!1,allowTransparency:!1,tabStopWidth:8,theme:{},rightClickSelectsWord:r.isMac,windowOptions:{},windowsMode:!1,wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1,overviewRulerWidth:0},["normal","bold","100","200","300","400","500","600","700","800","900"]);s.OptionsService=class{constructor(e){this._onOptionChange=new i.EventEmitter;var t=Object.assign({},s.DEFAULT_OPTIONS);for(const s in e)if(s in t)try{const i=e[s];t[s]=this._sanitizeAndValidateOption(s,i)}catch(e){console.error(e)}this.rawOptions=t,this.options=Object.assign({},t),this._setupOptions()}get onOptionChange(){return this._onOptionChange.event}_setupOptions(){var e=e=>{if(e in s.DEFAULT_OPTIONS)return this.rawOptions[e];throw new Error(`No option with key "${e}"`)},t=(e,t)=>{if(!(e in s.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);t=this._sanitizeAndValidateOption(e,t),this.rawOptions[e]!==t&&(this.rawOptions[e]=t,this._onOptionChange.fire(e))};for(const s in this.rawOptions){var i={get:e.bind(this,s),set:t.bind(this,s)};Object.defineProperty(this.options,s,i)}}_sanitizeAndValidateOption(e,t){switch(e){case"cursorStyle":if("block"!==(t=t||s.DEFAULT_OPTIONS[e])&&"underline"!==t&&"bar"!==t)throw new Error(`"${t}" is not a valid value for `+e);break;case"wordSeparator":t=t||s.DEFAULT_OPTIONS[e];break;case"fontWeight":case"fontWeightBold":"number"==typeof t&&1<=t&&t<=1e3||(t=n.includes(t)?t:s.DEFAULT_OPTIONS[e]);break;case"cursorWidth":t=Math.floor(t);case"lineHeight":case"tabStopWidth":if(t<1)throw new Error(e+" cannot be less than 1, value: "+t);break;case"minimumContrastRatio":t=Math.max(1,Math.min(21,Math.round(10*t)/10));break;case"scrollback":if((t=Math.min(t,4294967295))<0)throw new Error(e+" cannot be less than 0, value: "+t);break;case"fastScrollSensitivity":case"scrollSensitivity":if(t<=0)throw new Error(e+" cannot be less than or equal to 0, value: "+t);case"rows":case"cols":if(!t&&0!==t)throw new Error(e+" must be numeric, value: "+t)}return t}}},2660:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;0<=a;a--)(r=e[a])&&(o=(n<3?r(o):3this._removeMarkerFromLink(s,i)),this._dataByLinkId.set(s.id,s),s.id}const i=e,s=this._getEntryIdKey(i),r=this._entriesWithId.get(s);if(r)return this.addLineToLink(r.id,t.ybase+t.y),r.id;const n=t.addMarker(t.ybase+t.y),o={id:this._nextId++,key:this._getEntryIdKey(i),data:i,lines:[n]};return n.onDispose(()=>this._removeMarkerFromLink(o,n)),this._entriesWithId.set(o.key,o),this._dataByLinkId.set(o.id,o),o.id}addLineToLink(e,t){const i=this._dataByLinkId.get(e);if(i&&i.lines.every(e=>e.line!==t)){const e=this._bufferService.buffer.addMarker(t);i.lines.push(e),e.onDispose(()=>this._removeMarkerFromLink(i,e))}}getLinkData(e){return null==(e=this._dataByLinkId.get(e))?void 0:e.data}_getEntryIdKey(e){return e.id+";;"+e.uri}_removeMarkerFromLink(e,t){t=e.lines.indexOf(t);-1!==t&&(e.lines.splice(t,1),0===e.lines.length)&&(void 0!==e.data.id&&this._entriesWithId.delete(e.key),this._dataByLinkId.delete(e.id))}},n=s([r(0,i.IBufferService)],n);t.OscLinkService=n},8343:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0,t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e.di$dependencies||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);function r(e,t,i){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");var s;s=r,i=i,(e=e).di$target===e?e.di$dependencies.push({id:s,index:i}):(e.di$dependencies=[{id:s,index:i}],e.di$target=e)}return r.toString=()=>e,t.serviceRegistry.set(e,r),r}},2585:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IDecorationService=t.IUnicodeService=t.IOscLinkService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.IDirtyRowService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;var s,i=i(8343);t.IBufferService=(0,i.createDecorator)("BufferService"),t.ICoreMouseService=(0,i.createDecorator)("CoreMouseService"),t.ICoreService=(0,i.createDecorator)("CoreService"),t.ICharsetService=(0,i.createDecorator)("CharsetService"),t.IDirtyRowService=(0,i.createDecorator)("DirtyRowService"),t.IInstantiationService=(0,i.createDecorator)("InstantiationService"),(s=t.LogLevelEnum||(t.LogLevelEnum={}))[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.OFF=4]="OFF",t.ILogService=(0,i.createDecorator)("LogService"),t.IOptionsService=(0,i.createDecorator)("OptionsService"),t.IOscLinkService=(0,i.createDecorator)("OscLinkService"),t.IUnicodeService=(0,i.createDecorator)("UnicodeService"),t.IDecorationService=(0,i.createDecorator)("DecorationService")},1480:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;const s=i(8460),r=i(225);t.UnicodeService=class{constructor(){this._providers=Object.create(null),this._active="",this._onChange=new s.EventEmitter;var e=new r.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}get onChange(){return this._onChange.event}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(i){let s=0;var r=i.length;for(let t=0;t=r)return s+this.wcwidth(e);var n=i.charCodeAt(t);56320<=n&&n<=57343?e=1024*(e-55296)+n-56320+65536:s+=this.wcwidth(n)}s+=this.wcwidth(e)}return s}}}},s={};function r(e){var t=s[e];return void 0!==t||(t=s[e]={exports:{}},i[e].call(t.exports,t,t.exports,r)),t.exports}var e={};{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;const n=r(3236),o=r(9042),a=r(7975),h=r(7090),l=r(5741),c=r(8285),_=["cols","rows"];t.Terminal=class{constructor(e){this._core=new n.Terminal(e),this._addonManager=new l.AddonManager,this._publicOptions=Object.assign({},this._core.options);var t=e=>this._core.options[e],i=(e,t)=>{this._checkReadonlyOptions(e),this._core.options[e]=t};for(const e in this._core.options){const n={get:t.bind(this,e),set:i.bind(this,e)};Object.defineProperty(this._publicOptions,e,n)}}_checkReadonlyOptions(e){if(_.includes(e))throw new Error(`Option "${e}" can only be set in the constructor`)}_checkProposedApi(){if(!this._core.optionsService.rawOptions.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")}get onBell(){return this._core.onBell}get onBinary(){return this._core.onBinary}get onCursorMove(){return this._core.onCursorMove}get onData(){return this._core.onData}get onKey(){return this._core.onKey}get onLineFeed(){return this._core.onLineFeed}get onRender(){return this._core.onRender}get onResize(){return this._core.onResize}get onScroll(){return this._core.onScroll}get onSelectionChange(){return this._core.onSelectionChange}get onTitleChange(){return this._core.onTitleChange}get onWriteParsed(){return this._core.onWriteParsed}get element(){return this._core.element}get parser(){return this._checkProposedApi(),this._parser||(this._parser=new a.ParserApi(this._core)),this._parser}get unicode(){return this._checkProposedApi(),new h.UnicodeApi(this._core)}get textarea(){return this._core.textarea}get rows(){return this._core.rows}get cols(){return this._core.cols}get buffer(){return this._checkProposedApi(),this._buffer||(this._buffer=new c.BufferNamespaceApi(this._core)),this._buffer}get markers(){return this._checkProposedApi(),this._core.markers}get modes(){var e=this._core.coreService.decPrivateModes;let t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}}get options(){return this._publicOptions}set options(e){for(const t in e)this._publicOptions[t]=e[t]}blur(){this._core.blur()}focus(){this._core.focus()}resize(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)}open(e){this._core.open(e)}attachCustomKeyEventHandler(e){this._core.attachCustomKeyEventHandler(e)}registerLinkProvider(e){return this._checkProposedApi(),this._core.registerLinkProvider(e)}registerCharacterJoiner(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)}deregisterCharacterJoiner(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)}registerMarker(e=0){return this._verifyIntegers(e),this._core.addMarker(e)}registerDecoration(e){var t;return this._checkProposedApi(),this._verifyPositiveIntegers(null!=(t=e.x)?t:0,null!=(t=e.width)?t:0,null!=(t=e.height)?t:0),this._core.registerDecoration(e)}hasSelection(){return this._core.hasSelection()}select(e,t,i){this._verifyIntegers(e,t,i),this._core.select(e,t,i)}getSelection(){return this._core.getSelection()}getSelectionPosition(){return this._core.getSelectionPosition()}clearSelection(){this._core.clearSelection()}selectAll(){this._core.selectAll()}selectLines(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)}dispose(){this._addonManager.dispose(),this._core.dispose()}scrollLines(e){this._verifyIntegers(e),this._core.scrollLines(e)}scrollPages(e){this._verifyIntegers(e),this._core.scrollPages(e)}scrollToTop(){this._core.scrollToTop()}scrollToBottom(){this._core.scrollToBottom()}scrollToLine(e){this._verifyIntegers(e),this._core.scrollToLine(e)}clear(){this._core.clear()}write(e,t){this._core.write(e,t)}writeln(e,t){this._core.write(e),this._core.write("\r\n",t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){return this._addonManager.loadAddon(this,e)}static get strings(){return o}_verifyIntegers(...e){for(const t of e)if(t===1/0||isNaN(t)||t%1!=0)throw new Error("This API only accepts integers")}_verifyPositiveIntegers(...e){for(const t of e)if(t&&(t===1/0||isNaN(t)||t%1!=0||t<0))throw new Error("This API only accepts positive integers")}}}return e})()}) \ No newline at end of file +((e,t)=>{if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i,r=t();for(i in r)("object"==typeof exports?exports:e)[i]=r[i]}})(self,function(){var i={4567:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;let r=i(9042),s=i(6114),n=i(9924),o=i(3656),a=i(844),h=i(5596),l=i(9631);class c extends a.Disposable{constructor(e,t){super(),this._terminal=e,this._renderService=t,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityTreeRoot=document.createElement("div"),this._accessibilityTreeRoot.classList.add("xterm-accessibility"),this._accessibilityTreeRoot.tabIndex=0,this._rowContainer=document.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;ethis._onBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._onBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityTreeRoot.appendChild(this._rowContainer),this._renderRowsDebouncer=new n.TimeBasedDebouncer(this._renderRows.bind(this)),this._refreshRows(),this._liveRegion=document.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityTreeRoot.appendChild(this._liveRegion),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityTreeRoot),this.register(this._renderRowsDebouncer),this.register(this._terminal.onResize(e=>this._onResize(e.rows))),this.register(this._terminal.onRender(e=>this._refreshRows(e.start,e.end))),this.register(this._terminal.onScroll(()=>this._refreshRows())),this.register(this._terminal.onA11yChar(e=>this._onChar(e))),this.register(this._terminal.onLineFeed(()=>this._onChar("\n"))),this.register(this._terminal.onA11yTab(e=>this._onTab(e))),this.register(this._terminal.onKey(e=>this._onKey(e.key))),this.register(this._terminal.onBlur(()=>this._clearLiveRegion())),this.register(this._renderService.onDimensionsChange(()=>this._refreshRowsDimensions())),this._screenDprMonitor=new h.ScreenDprMonitor(window),this.register(this._screenDprMonitor),this._screenDprMonitor.setListener(()=>this._refreshRowsDimensions()),this.register((0,o.addDisposableDomListener)(window,"resize",()=>this._refreshRowsDimensions()))}dispose(){super.dispose(),(0,l.removeElementFromParent)(this._accessibilityTreeRoot),this._rowElements.length=0}_onBoundaryFocus(i,r){var s=i.target,e=this._rowElements[0===r?1:this._rowElements.length-2];if(s.getAttribute("aria-posinset")!==(0===r?"1":""+this._terminal.buffer.lines.length)&&i.relatedTarget===e){let e,t;if(0===r?(e=s,t=this._rowElements.pop(),this._rowContainer.removeChild(t)):(e=this._rowElements.shift(),t=s,this._rowContainer.removeChild(e)),e.removeEventListener("focus",this._topBoundaryFocusListener),t.removeEventListener("focus",this._bottomBoundaryFocusListener),0===r){let e=this._createAccessibilityTreeNode();this._rowElements.unshift(e),this._rowContainer.insertAdjacentElement("afterbegin",e)}else{let e=this._createAccessibilityTreeNode();this._rowElements.push(e),this._rowContainer.appendChild(e)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===r?-1:1),this._rowElements[0===r?1:this._rowElements.length-2].focus(),i.preventDefault(),i.stopImmediatePropagation()}}_onResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){var e=document.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_onTab(t){for(let e=0;e{this._accessibilityTreeRoot.appendChild(this._liveRegion)},0)}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0,s.isMac&&(0,l.removeElementFromParent)(this._liveRegion)}_onKey(e){this._clearLiveRegion(),this._charsToConsume.push(e)}_refreshRows(e,t){this._renderRowsDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){var s=this._terminal.buffer,n=s.lines.length.toString();for(let r=e;r<=t;r++){let e=s.translateBufferLineToString(s.ydisp+r,!0),t=(s.ydisp+r+1).toString(),i=this._rowElements[r];i&&(0===e.length?i.innerText=" ":i.textContent=e,i.setAttribute("aria-posinset",t),i.setAttribute("aria-setsize",n))}this._announceCharacters()}_refreshRowsDimensions(){if(this._renderService.dimensions.actualCellHeight){this._rowElements.length!==this._terminal.rows&&this._onResize(this._terminal.rows);for(let e=0;e{function r(e){return e.replace(/\r?\n/g,"\r")}function s(e,t){return t?"[200~"+e+"[201~":e}function n(e,t,i){e=s(e=r(e),i.decPrivateModes.bracketedPasteMode),i.triggerDataEvent(e,!0),t.value=""}function o(e,t,i){var i=i.getBoundingClientRect(),r=e.clientX-i.left-10,e=e.clientY-i.top-10;t.style.width="20px",t.style.height="20px",t.style.left=r+"px",t.style.top=e+"px",t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=r,t.bracketTextForPaste=s,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,i){e.stopPropagation(),e.clipboardData&&n(e.clipboardData.getData("text/plain"),t,i)},t.paste=n,t.moveTextAreaUnderMouseCursor=o,t.rightClickHandler=function(e,t,i,r,s){o(e,t,i),s&&r.rightClickSelect(e),t.value=r.selectionText,t.select()}},7239:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;let r=i(1505);t.ColorContrastCache=class{constructor(){this._color=new r.TwoKeyMap,this._css=new r.TwoKeyMap}setCss(e,t,i){this._css.set(e,t,i)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,i){this._color.set(e,t,i)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},5680:(e,r,t)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.ColorManager=r.DEFAULT_ANSI_COLORS=void 0;let h=t(8055),i=t(7239),s=h.css.toColor("#ffffff"),n=h.css.toColor("#000000"),o=h.css.toColor("#ffffff"),a=h.css.toColor("#000000"),l={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};r.DEFAULT_ANSI_COLORS=Object.freeze((()=>{var t=[h.css.toColor("#2e3436"),h.css.toColor("#cc0000"),h.css.toColor("#4e9a06"),h.css.toColor("#c4a000"),h.css.toColor("#3465a4"),h.css.toColor("#75507b"),h.css.toColor("#06989a"),h.css.toColor("#d3d7cf"),h.css.toColor("#555753"),h.css.toColor("#ef2929"),h.css.toColor("#8ae234"),h.css.toColor("#fce94f"),h.css.toColor("#729fcf"),h.css.toColor("#ad7fa8"),h.css.toColor("#34e2e2"),h.css.toColor("#eeeeec")],i=[0,95,135,175,215,255];for(let e=0;e<216;e++){var r=i[e/36%6|0],s=i[e/6%6|0],n=i[e%6];t.push({css:h.channels.toCss(r,s,n),rgba:h.channels.toRgba(r,s,n)})}for(let e=0;e<24;e++){var o=8+10*e;t.push({css:h.channels.toCss(o,o,o),rgba:h.channels.toRgba(o,o,o)})}return t})()),r.ColorManager=class{constructor(e,t){this.allowTransparency=t;t=e.createElement("canvas"),t.width=1,t.height=1,e=t.getContext("2d");if(!e)throw new Error("Could not get rendering context");this._ctx=e,this._ctx.globalCompositeOperation="copy",this._litmusColor=this._ctx.createLinearGradient(0,0,1,1),this._contrastCache=new i.ColorContrastCache,this.colors={foreground:s,background:n,cursor:o,cursorAccent:a,selectionForeground:void 0,selectionBackgroundTransparent:l,selectionBackgroundOpaque:h.color.blend(n,l),selectionInactiveBackgroundTransparent:l,selectionInactiveBackgroundOpaque:h.color.blend(n,l),ansi:r.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache},this._updateRestoreColors()}onOptionsChange(e,t){switch(e){case"minimumContrastRatio":this._contrastCache.clear();break;case"allowTransparency":this.allowTransparency=t}}setTheme(i={}){this.colors.foreground=this._parseColor(i.foreground,s),this.colors.background=this._parseColor(i.background,n),this.colors.cursor=this._parseColor(i.cursor,o,!0),this.colors.cursorAccent=this._parseColor(i.cursorAccent,a,!0),this.colors.selectionBackgroundTransparent=this._parseColor(i.selectionBackground,l,!0),this.colors.selectionBackgroundOpaque=h.color.blend(this.colors.background,this.colors.selectionBackgroundTransparent),this.colors.selectionInactiveBackgroundTransparent=this._parseColor(i.selectionInactiveBackground,this.colors.selectionBackgroundTransparent,!0),this.colors.selectionInactiveBackgroundOpaque=h.color.blend(this.colors.background,this.colors.selectionInactiveBackgroundTransparent);let e={css:"",rgba:0};if(this.colors.selectionForeground=i.selectionForeground?this._parseColor(i.selectionForeground,e):void 0,this.colors.selectionForeground===e&&(this.colors.selectionForeground=void 0),h.color.isOpaque(this.colors.selectionBackgroundTransparent))this.colors.selectionBackgroundTransparent=h.color.opacity(this.colors.selectionBackgroundTransparent,.3);if(h.color.isOpaque(this.colors.selectionInactiveBackgroundTransparent))this.colors.selectionInactiveBackgroundTransparent=h.color.opacity(this.colors.selectionInactiveBackgroundTransparent,.3);if(this.colors.ansi=r.DEFAULT_ANSI_COLORS.slice(),this.colors.ansi[0]=this._parseColor(i.black,r.DEFAULT_ANSI_COLORS[0]),this.colors.ansi[1]=this._parseColor(i.red,r.DEFAULT_ANSI_COLORS[1]),this.colors.ansi[2]=this._parseColor(i.green,r.DEFAULT_ANSI_COLORS[2]),this.colors.ansi[3]=this._parseColor(i.yellow,r.DEFAULT_ANSI_COLORS[3]),this.colors.ansi[4]=this._parseColor(i.blue,r.DEFAULT_ANSI_COLORS[4]),this.colors.ansi[5]=this._parseColor(i.magenta,r.DEFAULT_ANSI_COLORS[5]),this.colors.ansi[6]=this._parseColor(i.cyan,r.DEFAULT_ANSI_COLORS[6]),this.colors.ansi[7]=this._parseColor(i.white,r.DEFAULT_ANSI_COLORS[7]),this.colors.ansi[8]=this._parseColor(i.brightBlack,r.DEFAULT_ANSI_COLORS[8]),this.colors.ansi[9]=this._parseColor(i.brightRed,r.DEFAULT_ANSI_COLORS[9]),this.colors.ansi[10]=this._parseColor(i.brightGreen,r.DEFAULT_ANSI_COLORS[10]),this.colors.ansi[11]=this._parseColor(i.brightYellow,r.DEFAULT_ANSI_COLORS[11]),this.colors.ansi[12]=this._parseColor(i.brightBlue,r.DEFAULT_ANSI_COLORS[12]),this.colors.ansi[13]=this._parseColor(i.brightMagenta,r.DEFAULT_ANSI_COLORS[13]),this.colors.ansi[14]=this._parseColor(i.brightCyan,r.DEFAULT_ANSI_COLORS[14]),this.colors.ansi[15]=this._parseColor(i.brightWhite,r.DEFAULT_ANSI_COLORS[15]),i.extendedAnsi){let t=Math.min(this.colors.ansi.length-16,i.extendedAnsi.length);for(let e=0;eNumber(e)),s=Math.round(255*r);return{rgba:h.channels.toRgba(e,t,i,s),css:n}}}}},9631:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.removeElementFromParent=void 0,t.removeElementFromParent=function(...e){var t,i;for(i of e)null!=(t=null==i?void 0:i.parentElement)&&t.removeChild(i)}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,i,r){e.addEventListener(t,i,r);let s=!1;return{dispose:()=>{s||(s=!0,e.removeEventListener(t,i,r))}}}},6465:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3{var e=this._linkProviders.indexOf(t);-1!==e&&this._linkProviders.splice(e,1)}}}attachToDom(e,t,i){this._element=e,this._mouseService=t,this._renderService=i,this.register((0,h.addDisposableDomListener)(this._element,"mouseleave",()=>{this._isMouseOut=!0,this._clearCurrentLink()})),this.register((0,h.addDisposableDomListener)(this._element,"mousemove",this._onMouseMove.bind(this))),this.register((0,h.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,h.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_onMouseMove(t){if(this._lastMouseEvent=t,this._element&&this._mouseService){let e=this._positionFromMouseEvent(t,this._element,this._mouseService);if(e){this._isMouseOut=!1;var i=t.composedPath();for(let t=0;t{null!=e&&e.forEach(e=>{e.link.dispose&&e.link.dispose()})}),this._activeProviderReplies=new Map,this._activeLine=r.y);let n=!1;for(let[i,e]of this._linkProviders.entries())t?null!=(s=this._activeProviderReplies)&&s.get(i)&&(n=this._checkLinkProviderResult(i,r,n)):e.provideLinks(r.y,e=>{var t;this._isMouseOut||(e=null==e?void 0:e.map(e=>({link:e})),null!=(t=this._activeProviderReplies)&&t.set(i,e),n=this._checkLinkProviderResult(i,r,n),(null==(t=this._activeProviderReplies)?void 0:t.size)===this._linkProviders.length&&this._removeIntersectingLinks(r.y,this._activeProviderReplies))})}_removeIntersectingLinks(i,t){var r=new Set;for(let e=0;ei?this._bufferService.cols:n.link.range.end.x;for(let e=o;e<=a;e++){if(r.has(e)){s.splice(t--,1);break}r.add(e)}}}}_checkLinkProviderResult(r,s,n){var o;if(this._activeProviderReplies){let t=this._activeProviderReplies.get(r),i=!1;for(let e=0;ethis._linkAtPosition(e.link,s));e&&(n=!0,this._handleNewLink(e))}if(this._activeProviderReplies.size===this._linkProviders.length&&!n)for(let t=0;tthis._linkAtPosition(e.link,s));if(e){n=!0,this._handleNewLink(e);break}}}return n}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){var t;this._element&&this._mouseService&&this._currentLink&&(t=this._positionFromMouseEvent(e,this._element,this._mouseService))&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._element&&this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),(this._currentLink=void 0,a.disposeArray)(this._linkCacheDisposables))}_handleNewLink(i){var e;this._element&&this._lastMouseEvent&&this._mouseService&&(e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService))&&this._linkAtPosition(i.link,e)&&(this._currentLink=i,this._currentLink.state={decorations:{underline:void 0===i.link.decorations||i.link.decorations.underline,pointerCursor:void 0===i.link.decorations||i.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,i.link,this._lastMouseEvent),i.link.decorations={},Object.defineProperties(i.link.decorations,{pointerCursor:{get:()=>{var e;return null==(e=null==(e=this._currentLink)?void 0:e.state)?void 0:e.decorations.pointerCursor},set:e=>{var t;null!=(t=this._currentLink)&&t.state&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered)&&(null!=(t=this._element)&&t.classList.toggle("xterm-cursor-pointer",e))}},underline:{get:()=>{var e;return null==(e=null==(e=this._currentLink)?void 0:e.state)?void 0:e.decorations.underline},set:e=>{var t;null!=(t=this._currentLink)&&t.state&&(null==(t=null==(t=this._currentLink)?void 0:t.state)?void 0:t.decorations.underline)!==e&&(this._currentLink.state.decorations.underline=e,this._currentLink.state.isHovered)&&this._fireUnderlineEvent(i.link,e)}}}),this._renderService)&&this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange(e=>{var t=0===e.start?0:e.start+1+this._bufferService.buffer.ydisp;this._clearCurrentLink(t,e.end+1+this._bufferService.buffer.ydisp)}))}_linkHover(e,t,i){var r;null!=(r=this._currentLink)&&r.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor)&&e.classList.add("xterm-cursor-pointer"),t.hover&&t.hover(i,t.text)}_fireUnderlineEvent(e,t){var e=e.range,i=this._bufferService.buffer.ydisp,e=this._createLinkUnderlineEvent(e.start.x-1,e.start.y-i-1,e.end.x,e.end.y-i-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(e)}_linkLeave(e,t,i){var r;null!=(r=this._currentLink)&&r.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor)&&e.classList.remove("xterm-cursor-pointer"),t.leave&&t.leave(i,t.text)}_linkAtPosition(e,t){var i=e.range.start.y===e.range.end.y,r=e.range.start.yt.y;return(i&&e.range.start.x<=t.x&&e.range.end.x>=t.x||r&&e.range.end.x>=t.x||s&&e.range.start.x<=t.x||r&&s)&&e.range.start.y<=t.y&&e.range.end.y>=t.y}_positionFromMouseEvent(e,t,i){i=i.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(i)return{x:i[0],y:i[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,i,r,s){return{x1:e,y1:t,x2:i,y2:r,cols:this._bufferService.cols,fg:s}}},i=r([s(0,n.IBufferService)],i);t.Linkifier2=i},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},2962:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3{if(s)return s.activate(t,e,r);t=e;if(confirm(`Do you want to navigate to ${t}?`)){let e=window.open();if(e){try{e.opener=null}catch(e){}e.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}},hover:(e,t)=>{var i;return null==(i=null==s?void 0:s.hover)?void 0:i.call(s,e,t,r)},leave:(e,t)=>{var i;return null==(i=null==s?void 0:s.leave)?void 0:i.call(s,e,t,r)}})}h=!1,o=r.hasExtendedAttrs()&&r.extended.urlId?(a=t,r.extended.urlId):a=-1}}e(i)}else e(void 0)}};i=r([s(0,n.IBufferService),s(1,n.IOptionsService),s(2,n.IOscLinkService)],i),t.OscLinkProvider=i},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._parentWindow=e,this._renderCallback=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&(this._parentWindow.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||(this._animationFrame=this._parentWindow.requestAnimationFrame(()=>this._innerRefresh())),this._animationFrame}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=this._parentWindow.requestAnimationFrame(()=>this._innerRefresh()))}_innerRefresh(){var e,t;(this._animationFrame=void 0)!==this._rowStart&&void 0!==this._rowEnd&&void 0!==this._rowCount&&(e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1),this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(var e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},5596:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ScreenDprMonitor=void 0;i=i(844);class r extends i.Disposable{constructor(e){super(),this._parentWindow=e,this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio}setListener(e){this._listener&&this.clearListener(),this._listener=e,this._outerListener=()=>{this._listener&&(this._listener(this._parentWindow.devicePixelRatio,this._currentDevicePixelRatio),this._updateDpr())},this._updateDpr()}dispose(){super.dispose(),this.clearListener()}_updateDpr(){var e;this._outerListener&&(null!=(e=this._resolutionMediaMatchList)&&e.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._listener&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._listener=void 0,this._outerListener=void 0)}}t.ScreenDprMonitor=r},3236:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;let r=i(2950),s=i(1680),n=i(3614),o=i(2584),a=i(5435),h=i(9312),l=i(6114),c=i(3656),_=i(9042),d=i(4567),u=i(1296),f=i(7399),v=i(8460),g=i(8437),p=i(5680),S=i(3230),m=i(4725),C=i(428),b=i(8934),y=i(6465),w=i(5114),E=i(8969),L=i(8055),R=i(4269),k=i(5941),D=i(3107),A=i(5744),x=i(9074),B=i(2585),T=i(2962),M="undefined"!=typeof window?window.document:null;class O extends E.CoreTerminal{constructor(e={}){super(e),this.browser=l,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._onCursorMove=new v.EventEmitter,this._onKey=new v.EventEmitter,this._onRender=new v.EventEmitter,this._onSelectionChange=new v.EventEmitter,this._onTitleChange=new v.EventEmitter,this._onBell=new v.EventEmitter,this._onFocus=new v.EventEmitter,this._onBlur=new v.EventEmitter,this._onA11yCharEmitter=new v.EventEmitter,this._onA11yTabEmitter=new v.EventEmitter,this._setup(),this.linkifier2=this.register(this._instantiationService.createInstance(y.Linkifier2)),this.linkifier2.registerLinkProvider(this._instantiationService.createInstance(T.OscLinkProvider)),this._decorationService=this._instantiationService.createInstance(x.DecorationService),this._instantiationService.setService(B.IDecorationService,this._decorationService),this.register(this._inputHandler.onRequestBell(()=>this._onBell.fire())),this.register(this._inputHandler.onRequestRefreshRows((e,t)=>this.refresh(e,t))),this.register(this._inputHandler.onRequestSendFocus(()=>this._reportFocus())),this.register(this._inputHandler.onRequestReset(()=>this.reset())),this.register(this._inputHandler.onRequestWindowsOptionsReport(e=>this._reportWindowsOptions(e))),this.register(this._inputHandler.onColor(e=>this._handleColorEvent(e))),this.register((0,v.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,v.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,v.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,v.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize(e=>this._afterResize(e.cols,e.rows)))}get onCursorMove(){return this._onCursorMove.event}get onKey(){return this._onKey.event}get onRender(){return this._onRender.event}get onSelectionChange(){return this._onSelectionChange.event}get onTitleChange(){return this._onTitleChange.event}get onBell(){return this._onBell.event}get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}_handleColorEvent(e){var t;if(this._colorManager){for(let i of e){let e,t="";switch(i.index){case 256:e="foreground",t="10";break;case 257:e="background",t="11";break;case 258:e="cursor",t="12";break;default:e="ansi",t="4;"+i.index}switch(i.type){case 0:var r=L.color.toColorRGB("ansi"===e?this._colorManager.colors.ansi[i.index]:this._colorManager.colors[e]);this.coreService.triggerDataEvent(`${o.C0.ESC}]${t};`+(0,k.toRgbString)(r)+o.C1_ESCAPED.ST);break;case 1:"ansi"===e?this._colorManager.colors.ansi[i.index]=L.rgba.toColor(...i.color):this._colorManager.colors[e]=L.rgba.toColor(...i.color);break;case 2:this._colorManager.restoreColor(i.index)}}null!=(t=this._renderService)&&t.setColors(this._colorManager.colors),null!=(e=this.viewport)&&e.onThemeChange(this._colorManager.colors)}}dispose(){var e;this._isDisposed||(super.dispose(),null!=(e=this._renderService)&&e.dispose(),this._customKeyEventHandler=void 0,this.write=()=>{},null==(e=null==(e=this.element)?void 0:e.parentNode))||e.removeChild(this.element)}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_updateOptions(e){var t;switch(super._updateOptions(e),e){case"fontFamily":case"fontSize":null!=(t=this._renderService)&&t.clear(),null!=(t=this._charSizeService)&&t.measure();break;case"cursorBlink":case"cursorStyle":this.refresh(this.buffer.y,this.buffer.y);break;case"customGlyphs":case"drawBoldTextInBrightColors":case"letterSpacing":case"lineHeight":case"fontWeight":case"fontWeightBold":case"minimumContrastRatio":this._renderService&&(this._renderService.clear(),this._renderService.onResize(this.cols,this.rows),this.refresh(0,this.rows-1));break;case"scrollback":null!=(t=this.viewport)&&t.syncScrollArea();break;case"screenReaderMode":this.optionsService.rawOptions.screenReaderMode?!this._accessibilityManager&&this._renderService&&(this._accessibilityManager=new d.AccessibilityManager(this,this._renderService)):(null!=(t=this._accessibilityManager)&&t.dispose(),this._accessibilityManager=void 0);break;case"tabStopWidth":this.buffers.setupTabStops();break;case"theme":this._setTheme(this.optionsService.rawOptions.theme)}}_onTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(o.C0.ESC+"[I"),this.updateCursorStyle(e),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()}blur(){var e;return null==(e=this.textarea)?void 0:e.blur()}_onTextAreaBlur(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(o.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()}_syncTextArea(){var e,t,i,r;this.textarea&&this.buffer.isCursorInViewport&&!this._compositionHelper.isComposing&&this._renderService&&(t=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(t))&&(r=Math.min(this.buffer.x,this.cols-1),e=this._renderService.dimensions.actualCellHeight,t=t.getWidth(r),t=this._renderService.dimensions.actualCellWidth*t,i=this.buffer.y*this._renderService.dimensions.actualCellHeight,r=r*this._renderService.dimensions.actualCellWidth,this.textarea.style.left=r+"px",this.textarea.style.top=i+"px",this.textarea.style.width=t+"px",this.textarea.style.height=e+"px",this.textarea.style.lineHeight=e+"px",this.textarea.style.zIndex="-5")}_initGlobal(){this._bindKeys(),this.register((0,c.addDisposableDomListener)(this.element,"copy",e=>{this.hasSelection()&&(0,n.copyHandler)(e,this._selectionService)}));var e=e=>(0,n.handlePasteEvent)(e,this.textarea,this.coreService);this.register((0,c.addDisposableDomListener)(this.textarea,"paste",e)),this.register((0,c.addDisposableDomListener)(this.element,"paste",e)),l.isFirefox?this.register((0,c.addDisposableDomListener)(this.element,"mousedown",e=>{2===e.button&&(0,n.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)})):this.register((0,c.addDisposableDomListener)(this.element,"contextmenu",e=>{(0,n.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)})),l.isLinux&&this.register((0,c.addDisposableDomListener)(this.element,"auxclick",e=>{1===e.button&&(0,n.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)}))}_bindKeys(){this.register((0,c.addDisposableDomListener)(this.textarea,"keyup",e=>this._keyUp(e),!0)),this.register((0,c.addDisposableDomListener)(this.textarea,"keydown",e=>this._keyDown(e),!0)),this.register((0,c.addDisposableDomListener)(this.textarea,"keypress",e=>this._keyPress(e),!0)),this.register((0,c.addDisposableDomListener)(this.textarea,"compositionstart",()=>this._compositionHelper.compositionstart())),this.register((0,c.addDisposableDomListener)(this.textarea,"compositionupdate",e=>this._compositionHelper.compositionupdate(e))),this.register((0,c.addDisposableDomListener)(this.textarea,"compositionend",()=>this._compositionHelper.compositionend())),this.register((0,c.addDisposableDomListener)(this.textarea,"input",e=>this._inputEvent(e),!0)),this.register(this.onRender(()=>this._compositionHelper.updateCompositionElements()))}open(e){if(!e)throw new Error("Terminal requires a parent element.");e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this._document=e.ownerDocument,this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),this.element.setAttribute("tabindex","0"),e.appendChild(this.element);var e=M.createDocumentFragment(),t=(this._viewportElement=M.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),e.appendChild(this._viewportElement),this._viewportScrollArea=M.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=M.createElement("div"),this.screenElement.classList.add("xterm-screen"),this._helperContainer=M.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),e.appendChild(this.screenElement),this.textarea=M.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",_.promptLabel),this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this.register((0,c.addDisposableDomListener)(this.textarea,"focus",e=>this._onTextAreaFocus(e))),this.register((0,c.addDisposableDomListener)(this.textarea,"blur",()=>this._onTextAreaBlur())),this._helperContainer.appendChild(this.textarea),this._coreBrowserService=this._instantiationService.createInstance(w.CoreBrowserService,this.textarea,null!=(t=this._document.defaultView)?t:window),this._instantiationService.setService(m.ICoreBrowserService,this._coreBrowserService),this._charSizeService=this._instantiationService.createInstance(C.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(m.ICharSizeService,this._charSizeService),this._theme=this.options.theme||this._theme,this._colorManager=new p.ColorManager(M,this.options.allowTransparency),this.register(this.optionsService.onOptionChange(e=>this._colorManager.onOptionsChange(e,this.optionsService.rawOptions[e]))),this._colorManager.setTheme(this._theme),this._characterJoinerService=this._instantiationService.createInstance(R.CharacterJoinerService),this._instantiationService.setService(m.ICharacterJoinerService,this._characterJoinerService),this._createRenderer());this._renderService=this.register(this._instantiationService.createInstance(S.RenderService,t,this.rows,this.screenElement)),this._instantiationService.setService(m.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange(e=>this._onRender.fire(e))),this.onResize(e=>this._renderService.resize(e.cols,e.rows)),this._compositionView=M.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(r.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this.element.appendChild(e),this._mouseService=this._instantiationService.createInstance(b.MouseService),this._instantiationService.setService(m.IMouseService,this._mouseService),this.viewport=this._instantiationService.createInstance(s.Viewport,e=>this.scrollLines(e,!0,1),this._viewportElement,this._viewportScrollArea,this.element),this.viewport.onThemeChange(this._colorManager.colors),this.register(this._inputHandler.onRequestSyncScrollBar(()=>this.viewport.syncScrollArea())),this.register(this.viewport),this.register(this.onCursorMove(()=>{this._renderService.onCursorMove(),this._syncTextArea()})),this.register(this.onResize(()=>this._renderService.onResize(this.cols,this.rows))),this.register(this.onBlur(()=>this._renderService.onBlur())),this.register(this.onFocus(()=>this._renderService.onFocus())),this.register(this._renderService.onDimensionsChange(()=>this.viewport.syncScrollArea())),this._selectionService=this.register(this._instantiationService.createInstance(h.SelectionService,this.element,this.screenElement,this.linkifier2)),this._instantiationService.setService(m.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines(e=>this.scrollLines(e.amount,e.suppressScrollEvent))),this.register(this._selectionService.onSelectionChange(()=>this._onSelectionChange.fire())),this.register(this._selectionService.onRequestRedraw(e=>this._renderService.onSelectionChanged(e.start,e.end,e.columnSelectMode))),this.register(this._selectionService.onLinuxMouseSelection(e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()})),this.register(this._onScroll.event(e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()})),this.register((0,c.addDisposableDomListener)(this._viewportElement,"scroll",()=>this._selectionService.refresh())),this.linkifier2.attachToDom(this.screenElement,this._mouseService,this._renderService),this.register(this._instantiationService.createInstance(D.BufferDecorationRenderer,this.screenElement)),this.register((0,c.addDisposableDomListener)(this.element,"mousedown",e=>this._selectionService.onMouseDown(e))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager=new d.AccessibilityManager(this,this._renderService)),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(A.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onOptionChange(()=>{!this._overviewRulerRenderer&&this.options.overviewRulerWidth&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(A.OverviewRulerRenderer,this._viewportElement,this.screenElement)))}),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(u.DomRenderer,this._colorManager.colors,this.element,this.screenElement,this._viewportElement,this.linkifier2)}_setTheme(e){var t;this._theme=e,null!=(t=this._colorManager)&&t.setTheme(e),null!=(t=this._renderService)&&t.setColors(this._colorManager.colors),null!=(e=this.viewport)&&e.onThemeChange(this._colorManager.colors)}bindMouse(){let s=this,t=this.element;function i(i){var r=s._mouseService.getMouseReportCoords(i,s.screenElement);if(r){let e,t;switch(i.overrideType||i.type){case"mousemove":t=32,void 0===i.buttons?(e=3,void 0!==i.button&&(e=i.button<3?i.button:3)):e=1&i.buttons?0:4&i.buttons?1:2&i.buttons?2:3;break;case"mouseup":t=0,e=i.button<3?i.button:3;break;case"mousedown":t=1,e=i.button<3?i.button:3;break;case"wheel":if(0===s.viewport.getLinesScrolled(i))return;t=i.deltaY<0?0:1,e=4;break;default:return}void 0===t||void 0===e||4(i(e),e.buttons||(this._document.removeEventListener("mouseup",n.mouseup),n.mousedrag&&this._document.removeEventListener("mousemove",n.mousedrag)),this.cancel(e)),wheel:e=>(i(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&i(e)},mousemove:e=>{e.buttons||i(e)}};this.register(this.coreMouseService.onProtocolChange(e=>{e?("debug"===this.optionsService.rawOptions.logLevel&&this._logService.debug("Binding to mouse events:",this.coreMouseService.explainEvents(e)),this.element.classList.add("enable-mouse-events"),this._selectionService.disable()):(this._logService.debug("Unbinding from mouse events."),this.element.classList.remove("enable-mouse-events"),this._selectionService.enable()),8&e?n.mousemove||(t.addEventListener("mousemove",r.mousemove),n.mousemove=r.mousemove):(t.removeEventListener("mousemove",n.mousemove),n.mousemove=null),16&e?n.wheel||(t.addEventListener("wheel",r.wheel,{passive:!1}),n.wheel=r.wheel):(t.removeEventListener("wheel",n.wheel),n.wheel=null),2&e?n.mouseup||(n.mouseup=r.mouseup):(this._document.removeEventListener("mouseup",n.mouseup),n.mouseup=null),4&e?n.mousedrag||(n.mousedrag=r.mousedrag):(this._document.removeEventListener("mousemove",n.mousedrag),n.mousedrag=null)})),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,c.addDisposableDomListener)(t,"mousedown",e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return i(e),n.mouseup&&this._document.addEventListener("mouseup",n.mouseup),n.mousedrag&&this._document.addEventListener("mousemove",n.mousedrag),this.cancel(e)})),this.register((0,c.addDisposableDomListener)(t,"wheel",e=>{if(!n.wheel){if(this.buffer.hasScrollback)return this.viewport.onWheel(e)?this.cancel(e):void 0;{var i=this.viewport.getLinesScrolled(e);if(0===i)return;var r=o.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(e.deltaY<0?"A":"B");let t="";for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.onTouchStart(e),this.cancel(e)},{passive:!0})),this.register((0,c.addDisposableDomListener)(t,"touchmove",e=>this.coreMouseService.areMouseEventsActive||this.viewport.onTouchMove(e)?void 0:this.cancel(e),{passive:!1}))}refresh(e,t){var i;null!=(i=this._renderService)&&i.refreshRows(e,t)}updateCursorStyle(e){var t;null!=(t=this._selectionService)&&t.shouldColumnSelect(e)?this.element.classList.add("column-select"):this.element.classList.remove("column-select")}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,i=0){super.scrollLines(e,t,i),this.refresh(0,this.rows-1)}paste(e){(0,n.paste)(e,this.textarea,this.coreService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}registerLinkProvider(e){return this.linkifier2.registerLinkProvider(e)}registerCharacterJoiner(e){if(this._characterJoinerService)return e=this._characterJoinerService.register(e),this.refresh(0,this.rows-1),e;throw new Error("Terminal must be opened first")}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}addMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,i){this._selectionService.setSelection(e,t,i)}getSelection(){return this._selectionService?this._selectionService.selectionText:""}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){var e;null!=(e=this._selectionService)&&e.clearSelection()}selectAll(){var e;null!=(e=this._selectionService)&&e.selectAll()}selectLines(e,t){var i;null!=(i=this._selectionService)&&i.selectLines(e,t)}_keyDown(t){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(t))return!1;let e=this.browser.isMac&&this.options.macOptionIsMeta&&t.altKey;if(!e&&!this._compositionHelper.keydown(t))return this.buffer.ybase!==this.buffer.ydisp&&this._bufferService.scrollToBottom(),!1;e||"Dead"!==t.key&&"AltGraph"!==t.key||(this._unprocessedDeadKey=!0);var i=(0,f.evaluateKeyboardEvent)(t,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(t),3!==i.type&&2!==i.type)return 1===i.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,t)||(i.cancel&&this.cancel(t,!0),!i.key)||!!(t.key&&!t.ctrlKey&&!t.altKey&&!t.metaKey&&1===t.key.length&&65<=t.key.charCodeAt(0)&&t.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?!(this._unprocessedDeadKey=!1):(i.key!==o.C0.ETX&&i.key!==o.C0.CR||(this.textarea.value=""),this._onKey.fire({key:i.key,domEvent:t}),this._showCursor(),this.coreService.triggerDataEvent(i.key,!0),this.optionsService.rawOptions.screenReaderMode?void(this._keyDownHandled=!0):this.cancel(t,!0)));{let e=this.rows-1;return this.scrollLines(2===i.type?-e:e),this.cancel(t,!0)}}_isThirdLevelShift(e,t){e=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?e:e&&(!t.keyCode||47{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;i=Date.now();if(i-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=i,this._innerRefresh();else if(!this._additionalRefreshRequested){let e=i-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout(()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0},t)}}_innerRefresh(){var e,t;void 0!==this._rowStart&&void 0!==this._rowEnd&&void 0!==this._rowCount&&(e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1),this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t))}}},1680:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._activeBuffer=e.activeBuffer)),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange(e=>this._renderDimensions=e)),setTimeout(()=>this.syncScrollArea(),0)}onThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}_refresh(e){e?(this._innerRefresh(),null!==this._refreshAnimationFrame&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame)):null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame(()=>this._innerRefresh()))}_innerRefresh(){if(0this._smoothScroll()):this._clearSmoothScrollState())}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){var i=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||0this._queueRefresh())),this.register(this._renderService.onDimensionsChange(()=>{this._dimensionsChanged=!0,this._queueRefresh()})),this.register((0,n.addDisposableDomListener)(window,"resize",()=>this._queueRefresh())),this.register(this._bufferService.buffers.onBufferActivate(()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt})),this.register(this._decorationService.onDecorationRegistered(()=>this._queueRefresh())),this.register(this._decorationService.onDecorationRemoved(e=>this._removeDecoration(e)))}dispose(){this._container.remove(),this._decorationElements.clear(),super.dispose()}_queueRefresh(){void 0===this._animationFrame&&(this._animationFrame=this._renderService.addRefreshCallback(()=>{this.refreshDecorations(),this._animationFrame=void 0}))}refreshDecorations(){for(var e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){var t=document.createElement("div"),i=(t.classList.add("xterm-decoration"),t.style.width=Math.round((e.options.width||1)*this._renderService.dimensions.actualCellWidth)+"px",t.style.height=(e.options.height||1)*this._renderService.dimensions.actualCellHeight+"px",t.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.actualCellHeight+"px",t.style.lineHeight=this._renderService.dimensions.actualCellHeight+"px",null!=(i=e.options.x)?i:0);return i&&i>this._bufferService.cols&&(t.style.display="none"),this._refreshXPosition(e,t),t}_refreshStyle(t){var i=t.marker.line-this._bufferService.buffers.active.ydisp;if(i<0||i>=this._bufferService.rows)t.element&&(t.element.style.display="none",t.onRenderEmitter.fire(t.element));else{let e=this._decorationElements.get(t);e||(t.onDispose(()=>this._removeDecoration(t)),e=this._createElement(t),t.element=e,this._decorationElements.set(t,e),this._container.appendChild(e)),e.style.top=i*this._renderService.dimensions.actualCellHeight+"px",e.style.display=this._altBufferIsActive?"none":"block",t.onRenderEmitter.fire(e)}}_refreshXPosition(e,t=e.element){var i;t&&(i=null!=(i=e.options.x)?i:0,"right"===(e.options.anchor||"left")?t.style.right=i?i*this._renderService.dimensions.actualCellWidth+"px":"":t.style.left=i?i*this._renderService.dimensions.actualCellWidth+"px":"")}_removeDecoration(e){var t;null!=(t=this._decorationElements.get(e))&&t.remove(),this._decorationElements.delete(e)}},i=r([s(1,h.IBufferService),s(2,h.IDecorationService),s(3,o.IRenderService)],i);t.BufferDecorationRenderer=i},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(var t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,i){return t>=e.startBufferLine-this._linePadding[i||"full"]&&t<=e.endBufferLine+this._linePadding[i||"full"]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._queueRefresh(void 0,!0))),this.register(this._decorationService.onDecorationRemoved(()=>this._queueRefresh(void 0,!0)))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange(()=>this._queueRefresh())),this.register(this._bufferService.buffers.onBufferActivate(()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?"none":"block"})),this.register(this._bufferService.onScroll(()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())}))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender(()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)})),this.register(this._optionsService.onOptionChange(e=>{"overviewRulerWidth"===e&&this._queueRefresh(!0)})),this.register((0,n.addDisposableDomListener)(this._coreBrowseService.window,"resize",()=>{this._queueRefresh(!0)})),this._queueRefresh(!0)}dispose(){var e;null!=(e=this._canvas)&&e.remove(),super.dispose()}_refreshDrawConstants(){var e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);_.full=this._canvas.width,_.left=e,_.center=t,_.right=e,this._refreshDrawHeightConstants(),d.full=0,d.left=0,d.center=_.left,d.right=_.left+_.center}_refreshDrawHeightConstants(){c.full=Math.round(2*this._coreBrowseService.dpr);var e=this._canvas.height/this._bufferService.buffer.lines.length,e=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowseService.dpr);c.left=e,c.center=e,c.right=e}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=this._width+"px",this._canvas.width=Math.round(this._width*this._coreBrowseService.dpr),this._canvas.style.height=this._screenElement.clientHeight+"px",this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowseService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(let e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;let e=this._colorZoneStore.zones;for(var t of e)"full"!==t.position&&this._renderColorZone(t);for(var i of e)"full"===i.position&&this._renderColorZone(i);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(d[e.position||"full"],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-c[e.position||"full"]/2),_[e.position||"full"],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+c[e.position||"full"]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,void 0===this._animationFrame&&(this._animationFrame=this._coreBrowseService.window.requestAnimationFrame(()=>{this._refreshDecorations(),this._animationFrame=void 0}))}},i=r([s(2,l.IBufferService),s(3,l.IDecorationService),s(4,o.IRenderService),s(5,l.IOptionsService),s(6,o.ICoreBrowserService)],i);t.OverviewRulerRenderer=i},2950:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3{this._compositionPosition.end=this._textarea.value.length},0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(e){if(this._compositionView.classList.remove("active"),this._isComposing=!1,e){let t={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout(()=>{var e;this._isSendingComposition&&(this._isSendingComposition=!1,t.start+=this._dataAlreadySent.length,0<(e=this._isComposing?this._textarea.value.substring(t.start,t.end):this._textarea.value.substring(t.start)).length)&&this._coreService.triggerDataEvent(e,!0)},0)}else{this._isSendingComposition=!1;let e=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(e,!0)}}_handleAnyTextareaChanges(){let i=this._textarea.value;setTimeout(()=>{var e,t;this._isComposing||(t=(e=this._textarea.value).replace(i,""),this._dataAlreadySent=t,e.length>i.length?this._coreService.triggerDataEvent(t,!0):e.lengththis.updateCompositionElements(!0),0)}}},i=r([s(2,o.IBufferService),s(3,o.IOptionsService),s(4,o.ICoreService),s(5,n.IRenderService)],i);t.CompositionHelper=i},9806:(e,t)=>{function l(e,t,i){var r=i.getBoundingClientRect(),e=e.getComputedStyle(i),i=parseInt(e.getPropertyValue("padding-left")),e=parseInt(e.getPropertyValue("padding-top"));return[t.clientX-r.left-i,t.clientY-r.top-e]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=l,t.getCoords=function(e,t,i,r,s,n,o,a,h){return(n=n&&l(e,t,i))?(n[0]=Math.ceil((n[0]+(h?o/2:0))/o),n[1]=Math.ceil(n[1]/a),n[0]=Math.min(Math.max(n[0],1),r+(h?1:0)),n[1]=Math.min(Math.max(n[1],1),s),n):void 0}},9504:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;let r=i(2584);function f(e,t,i,r){var s=e-v(i,e),n=t-v(i,t);return S(Math.abs(s-n)-((r,s,n)=>{let o=0,a=r-v(n,r),e=s-v(n,s);for(let i=0;in.cols-1?(h+=n.buffer.translateBufferLineToString(a,!1,e,o),e=o=0,a++):!s&&o<0&&(h+=n.buffer.translateBufferLineToString(a,!1,0,e+1),e=o=n.cols-1,a--);return h+n.buffer.translateBufferLineToString(a,!1,e,o)}function p(e,t){t=t?"O":"[";return r.C0.ESC+t+e}function S(t,i){t=Math.floor(t);let r="";for(let e=0;e(s=0{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;i=i(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=i.isFirefox||i.isLegacyEdge?"bottom":"ideographic"},1752:(e,t)=>{function i(e){return 57508<=e&&e<=57558}Object.defineProperty(t,"__esModule",{value:!0}),t.excludeFromContrastRatioDemands=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(e)return e;throw new Error("value must not be falsy")},t.isPowerlineGlyph=i,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.excludeFromContrastRatioDemands=function(e){return i(e)||9472<=e&&e<=9631}},1296:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._onLinkHover(e))),this.register(this._linkifier2.onHideLinkUnderline(e=>this._onLinkLeave(e)))}get onRequestRedraw(){return(new l.EventEmitter).event}dispose(){this._element.classList.remove(u+this._terminalClass),(0,d.removeElementFromParent)(this._rowContainer,this._selectionContainer,this._themeStyleElement,this._dimensionsStyleElement),super.dispose()}_updateDimensions(){let e=this._coreBrowserService.dpr;this.dimensions.scaledCharWidth=this._charSizeService.width*e,this.dimensions.scaledCharHeight=Math.ceil(this._charSizeService.height*e),this.dimensions.scaledCellWidth=this.dimensions.scaledCharWidth+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.scaledCellHeight=Math.floor(this.dimensions.scaledCharHeight*this._optionsService.rawOptions.lineHeight),this.dimensions.scaledCharLeft=0,this.dimensions.scaledCharTop=0,this.dimensions.scaledCanvasWidth=this.dimensions.scaledCellWidth*this._bufferService.cols,this.dimensions.scaledCanvasHeight=this.dimensions.scaledCellHeight*this._bufferService.rows,this.dimensions.canvasWidth=Math.round(this.dimensions.scaledCanvasWidth/e),this.dimensions.canvasHeight=Math.round(this.dimensions.scaledCanvasHeight/e),this.dimensions.actualCellWidth=this.dimensions.canvasWidth/this._bufferService.cols,this.dimensions.actualCellHeight=this.dimensions.canvasHeight/this._bufferService.rows;for(let e of this._rowElements)e.style.width=this.dimensions.canvasWidth+"px",e.style.height=this.dimensions.actualCellHeight+"px",e.style.lineHeight=this.dimensions.actualCellHeight+"px",e.style.overflow="hidden";this._dimensionsStyleElement||(this._dimensionsStyleElement=document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));var t=`${this._terminalSelector} .xterm-rows span { display: inline-block; height: 100%; vertical-align: top; width: ${this.dimensions.actualCellWidth}px}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=this.dimensions.canvasWidth+"px",this._screenElement.style.height=this.dimensions.canvasHeight+"px"}setColors(e){this._colors=e,this._injectCss()}_injectCss(){this._themeStyleElement||(this._themeStyleElement=document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));let i=`${this._terminalSelector} .xterm-rows { color: ${this._colors.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px;}`;i=(i=(i=(i=(i+=`${this._terminalSelector} span:not(.${c.BOLD_CLASS}) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.${c.BOLD_CLASS} { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.${c.ITALIC_CLASS} { font-style: italic;}`)+"@keyframes blink_box_shadow_"+this._terminalClass+" { 50% { box-shadow: none; }}")+"@keyframes blink_block_"+this._terminalClass+" { 0% {"+` background-color: ${this._colors.cursor.css};`+` color: ${this._colors.cursorAccent.css}; } 50% {`+` background-color: ${this._colors.cursorAccent.css};`+` color: ${this._colors.cursor.css}; }}`)+`${this._terminalSelector} .xterm-rows:not(.xterm-focus) .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_BLOCK_CLASS} { outline: 1px solid ${this._colors.cursor.css}; outline-offset: -1px;}${this._terminalSelector} .xterm-rows.xterm-focus .${c.CURSOR_CLASS}.${c.CURSOR_BLINK_CLASS}:not(.${c.CURSOR_STYLE_BLOCK_CLASS}) { animation: blink_box_shadow_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .xterm-rows.xterm-focus .${c.CURSOR_CLASS}.${c.CURSOR_BLINK_CLASS}.${c.CURSOR_STYLE_BLOCK_CLASS} { animation: blink_block_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .xterm-rows.xterm-focus .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_BLOCK_CLASS} {`+` background-color: ${this._colors.cursor.css};`+` color: ${this._colors.cursorAccent.css};}`+`${this._terminalSelector} .xterm-rows .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_BAR_CLASS} {`+` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${this._colors.cursor.css} inset;}`+`${this._terminalSelector} .xterm-rows .${c.CURSOR_CLASS}.${c.CURSOR_STYLE_UNDERLINE_CLASS} {`+` box-shadow: 0 -1px 0 ${this._colors.cursor.css} inset;}`)+`${this._terminalSelector} .xterm-selection { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .xterm-selection div { position: absolute; background-color: ${this._colors.selectionBackgroundOpaque.css};}${this._terminalSelector} .xterm-selection div { position: absolute; background-color: ${this._colors.selectionInactiveBackgroundOpaque.css};}`,this._colors.ansi.forEach((e,t)=>{i+=`${this._terminalSelector} .xterm-fg-${t} { color: ${e.css}; }${this._terminalSelector} .xterm-bg-${t} { background-color: ${e.css}; }`}),i+=`${this._terminalSelector} .xterm-fg-${n.INVERTED_DEFAULT_COLOR} { color: ${_.color.opaque(this._colors.background).css}; }${this._terminalSelector} .xterm-bg-${n.INVERTED_DEFAULT_COLOR} { background-color: ${this._colors.foreground.css}; }`,this._themeStyleElement.textContent=i}onDevicePixelRatioChange(){this._updateDimensions()}_refreshRowElements(e,t){for(let e=this._rowElements.length;e<=t;e++){let e=document.createElement("div");this._rowContainer.appendChild(e),this._rowElements.push(e)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())}onResize(e,t){this._refreshRowElements(e,t),this._updateDimensions()}onCharSizeChanged(){this._updateDimensions()}onBlur(){this._rowContainer.classList.remove(f)}onFocus(){this._rowContainer.classList.add(f)}onSelectionChanged(i,r,e){for(;this._selectionContainer.children.length;)this._selectionContainer.removeChild(this._selectionContainer.children[0]);if(this._rowFactory.onSelectionChanged(i,r,e),this.renderRows(0,this._bufferService.rows-1),i&&r){var s=i[1]-this._bufferService.buffer.ydisp,n=r[1]-this._bufferService.buffer.ydisp,o=Math.max(s,0),a=Math.min(n,this._bufferService.rows-1);if(!(o>=this._bufferService.rows||a<0)){var h=document.createDocumentFragment();if(e){let e=i[0]>r[0];h.appendChild(this._createSelectionElement(o,(e?r:i)[0],(e?i:r)[0],a-o+1))}else{let e=s===o?i[0]:0,t=o===n?r[0]:this._bufferService.cols;if(h.appendChild(this._createSelectionElement(o,e,t)),h.appendChild(this._createSelectionElement(o+1,0,this._bufferService.cols,a-o-1)),o!==a){let e=n===a?r[0]:this._bufferService.cols;h.appendChild(this._createSelectionElement(a,0,e))}}this._selectionContainer.appendChild(h)}}}_createSelectionElement(e,t,i,r=1){var s=document.createElement("div");return s.style.height=r*this.dimensions.actualCellHeight+"px",s.style.top=e*this.dimensions.actualCellHeight+"px",s.style.left=t*this.dimensions.actualCellWidth+"px",s.style.width=this.dimensions.actualCellWidth*(i-t)+"px",s}onCursorMove(){}onOptionsChanged(){this._updateDimensions(),this._injectCss()}clear(){for(var e of this._rowElements)e.innerText=""}renderRows(e,t){var n=this._bufferService.buffer.ybase+this._bufferService.buffer.y,o=Math.min(this._bufferService.buffer.x,this._bufferService.cols-1),a=this._optionsService.rawOptions.cursorBlink;for(let s=e;s<=t;s++){let e=this._rowElements[s],t=(e.innerText="",s+this._bufferService.buffer.ydisp),i=this._bufferService.buffer.lines.get(t),r=this._optionsService.rawOptions.cursorStyle;e.appendChild(this._rowFactory.createRow(i,t,t===n,r,o,a,this.dimensions.actualCellWidth,this._bufferService.cols))}}get _terminalSelector(){return"."+u+this._terminalClass}_onLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_onLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(i,e,r,t,s,n){for(;i!==e||r!==t;){let e=this._rowElements[r];if(!e)return;let t=e.children[i];t&&(t.style.textDecoration=n?"underline":"none"),++i>=s&&(i=0,r++)}}};g=r([s(5,h.IInstantiationService),s(6,a.ICharSizeService),s(7,h.IOptionsService),s(8,h.IBufferService),s(9,a.ICoreBrowserService)],g),t.DomRenderer=g},3787:function(e,L,t){var i=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3=e)&&p<=i&&(p=e),!this._coreService.isCursorHidden&&v&&e===p)switch(y.classList.add(L.CURSOR_CLASS),S&&y.classList.add(L.CURSOR_BLINK_CLASS),g){case"bar":y.classList.add(L.CURSOR_STYLE_BAR_CLASS);break;case"underline":y.classList.add(L.CURSOR_STYLE_UNDERLINE_CLASS);break;default:y.classList.add(L.CURSOR_STYLE_BLOCK_CLASS)}if(r.isBold()&&y.classList.add(L.BOLD_CLASS),r.isItalic()&&y.classList.add(L.ITALIC_CLASS),r.isDim()&&y.classList.add(L.DIM_CLASS),r.isInvisible()?y.textContent=k.WHITESPACE_CELL_CHAR:y.textContent=r.getChars()||k.WHITESPACE_CELL_CHAR,r.isUnderline()&&(y.classList.add(L.UNDERLINE_CLASS+"-"+r.extended.underlineStyle)," "===y.textContent&&(y.innerHTML=" "),!r.isUnderlineColorDefault()))if(r.isUnderlineColorRGB())y.style.textDecorationColor=`rgb(${x.AttributeData.toColorRGB(r.getUnderlineColor()).join(",")})`;else{let e=r.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&r.isBold()&&e<8&&(e+=8),y.style.textDecorationColor=this._colors.ansi[e].css}r.isStrikethrough()&&y.classList.add(L.STRIKETHROUGH_CLASS);let s=r.getFgColor(),n=r.getFgColorMode(),o=r.getBgColor(),a=r.getBgColorMode();var w=!!r.isInverse();if(w){let e=s,t=(s=o,o=e,n);n=a,a=t}let h,l,c=!1;this._decorationService.forEachDecorationAtCell(e,f,void 0,e=>{"top"!==e.options.layer&&c||(e.backgroundColorRGB&&(a=50331648,o=e.backgroundColorRGB.rgba>>8&16777215,h=e.backgroundColorRGB),e.foregroundColorRGB&&(n=50331648,s=e.foregroundColorRGB.rgba>>8&16777215,l=e.foregroundColorRGB),c="top"===e.options.layer)});var E=this._isCellInSelection(e,f);let _;switch(c||this._colors.selectionForeground&&E&&(n=50331648,s=this._colors.selectionForeground.rgba>>8&16777215,l=this._colors.selectionForeground),E&&(h=this._coreBrowserService.isFocused?this._colors.selectionBackgroundOpaque:this._colors.selectionInactiveBackgroundOpaque,c=!0),c&&y.classList.add("xterm-decoration-top"),a){case 16777216:case 33554432:_=this._colors.ansi[o],y.classList.add("xterm-bg-"+o);break;case 50331648:_=D.rgba.toColor(o>>16,o>>8&255,255&o),this._addStyle(y,"background-color:#"+B((o>>>0).toString(16),"0",6));break;default:w?(_=this._colors.foreground,y.classList.add("xterm-bg-"+R.INVERTED_DEFAULT_COLOR)):_=this._colors.background}switch(h||r.isDim()&&(h=D.color.multiplyOpacity(_,.5)),n){case 16777216:case 33554432:r.isBold()&&s<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&(s+=8),this._applyMinimumContrast(y,_,this._colors.ansi[s],r,h,void 0)||y.classList.add("xterm-fg-"+s);break;case 50331648:let e=D.rgba.toColor(s>>16&255,s>>8&255,255&s);this._applyMinimumContrast(y,_,e,r,h,l)||this._addStyle(y,"color:#"+B(s.toString(16),"0",6));break;default:this._applyMinimumContrast(y,_,this._colors.foreground,r,h,void 0)||w&&y.classList.add("xterm-fg-"+R.INVERTED_DEFAULT_COLOR)}C.appendChild(y),e=i}}return C}_applyMinimumContrast(e,t,i,r,s,n){if(1===this._optionsService.rawOptions.minimumContrastRatio||(0,h.excludeFromContrastRatioDemands)(r.getCode()))return!1;let o;return void 0===(o=s||n?o:this._colors.contrastCache.getColor(t.rgba,i.rgba))&&(o=D.color.ensureContrastRatio(s||t,n||i,this._optionsService.rawOptions.minimumContrastRatio),this._colors.contrastCache.setColor((s||t).rgba,(n||i).rgba,null!=o?o:null)),!!o&&(this._addStyle(e,"color:"+o.css),!0)}_addStyle(e,t){e.setAttribute("style",`${e.getAttribute("style")||""}${t};`)}_isCellInSelection(e,t){var i=this._selectionStart,r=this._selectionEnd;return!(!i||!r)&&(this._columnSelectMode?i[0]<=r[0]?e>=i[0]&&t>=i[1]&&e=i[1]&&e>=r[0]&&t<=r[1]:t>i[1]&&t=i[0]&&e=i[0])}};function B(e,t,i){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){var e;return this.isSelectAllActive?[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1]:this.selectionStart?!this.selectionEnd||this.areSelectionValuesReversed()?(e=this.selectionStart[0]+this.selectionStartLength)>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]:this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]?(e=this.selectionStart[0]+this.selectionStartLength)>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]:this.selectionEnd:void 0}areSelectionValuesReversed(){var e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}onTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0,t.CoreBrowserService=class{constructor(e,t){this._textarea=e,this.window=t}get dpr(){return this.window.devicePixelRatio}get isFocused(){return(this._textarea.getRootNode?this._textarea.getRootNode():this._textarea.ownerDocument).activeElement===this._textarea&&this._textarea.ownerDocument.hasFocus()}}},8934:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3=this._renderService.dimensions.canvasWidth||e[1]>=this._renderService.dimensions.canvasHeight))return{col:Math.floor(e[0]/this._renderService.dimensions.actualCellWidth),row:Math.floor(e[1]/this._renderService.dimensions.actualCellHeight),x:Math.floor(e[0]),y:Math.floor(e[1])}}},i=r([s(0,n.IRenderService),s(1,n.ICharSizeService)],i);t.MouseService=i},3230:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._renderer.dispose()}),this._renderDebouncer=new h.RenderDebouncer(a.window,(e,t)=>this._renderRows(e,t)),this.register(this._renderDebouncer),this._screenDprMonitor=new c.ScreenDprMonitor(a.window),this._screenDprMonitor.setListener(()=>this.onDevicePixelRatioChange()),this.register(this._screenDprMonitor),this.register(o.onResize(()=>this._fullRefresh())),this.register(o.buffers.onBufferActivate(()=>{var e;return null==(e=this._renderer)?void 0:e.clear()})),this.register(r.onOptionChange(()=>this._handleOptionsChanged())),this.register(this._charSizeService.onCharSizeChange(()=>this.onCharSizeChanged())),this.register(n.onDecorationRegistered(()=>this._fullRefresh())),this.register(n.onDecorationRemoved(()=>this._fullRefresh())),this._renderer.onRequestRedraw(e=>this.refreshRows(e.start,e.end,!0)),this.register((0,_.addDisposableDomListener)(a.window,"resize",()=>this.onDevicePixelRatioChange())),"IntersectionObserver"in a.window){let e=new a.window.IntersectionObserver(e=>this._onIntersectionChange(e[e.length-1]),{threshold:0});e.observe(i),this.register({dispose:()=>e.disconnect()})}}get onDimensionsChange(){return this._onDimensionsChange.event}get onRenderedViewportChange(){return this._onRenderedViewportChange.event}get onRender(){return this._onRender.event}get onRefreshRequest(){return this._onRefreshRequest.event}get dimensions(){return this._renderer.dimensions}_onIntersectionChange(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,i=!1){this._isPaused?this._needsFullRefresh=!0:(i||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.onSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.onOptionsChanged(),this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize()}_fireOnCanvasResize(){this._renderer.dimensions.canvasWidth===this._canvasWidth&&this._renderer.dimensions.canvasHeight===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.dimensions)}dispose(){super.dispose()}setRenderer(e){this._renderer.dispose(),this._renderer=e,this._renderer.onRequestRedraw(e=>this.refreshRows(e.start,e.end,!0)),this._needsSelectionRefresh=!0,this._fullRefresh()}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){var e,t;null!=(t=null==(e=this._renderer)?void 0:e.clearTextureAtlas)&&t.call(e),this._fullRefresh()}setColors(e){this._renderer.setColors(e),this._fullRefresh()}onDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.onDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1)}onResize(e,t){this._renderer.onResize(e,t),this._fullRefresh()}onCharSizeChanged(){this._renderer.onCharSizeChanged()}onBlur(){this._renderer.onBlur()}onFocus(){this._renderer.onFocus()}onSelectionChanged(e,t,i){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=i,this._renderer.onSelectionChanged(e,t,i)}onCursorMove(){this._renderer.onCursorMove()}clear(){this._renderer.clear()}},i=r([s(3,o.IOptionsService),s(4,a.ICharSizeService),s(5,o.IDecorationService),s(6,o.IBufferService),s(7,a.ICoreBrowserService)],i);t.RenderService=i},9312:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._onMouseMove(e),this._mouseUpListener=e=>this._onMouseUp(e),this._coreService.onUserInput(()=>{this.hasSelection&&this.clearSelection()}),this._trimListener=this._bufferService.buffer.lines.onTrim(e=>this._onTrim(e)),this.register(this._bufferService.buffers.onBufferActivate(e=>this._onBufferActivate(e))),this.enable(),this._model=new l.SelectionModel(this._bufferService),this._activeSelectionMode=0}get onLinuxMouseSelection(){return this._onLinuxMouseSelection.event}get onRequestRedraw(){return this._onRedrawRequest.event}get onSelectionChange(){return this._onSelectionChange.event}get onRequestScrollLines(){return this._onRequestScrollLines.event}dispose(){this._removeMouseDownListeners()}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){var e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){let e=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;if(!e||!s)return"";var n=this._bufferService.buffer,o=[];if(3===this._activeSelectionMode){if(e[0]===s[0])return"";let i=(e[0]e.replace(g," ")).join(a.isWindows?"\r\n":"\n")}clearSelection(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()}refresh(e){this._refreshAnimationFrame||(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame(()=>this._refresh())),a.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)}_refresh(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})}_isClickInSelection(e){var e=this._getMouseBufferCoords(e),t=this._model.finalSelectionStart,i=this._model.finalSelectionEnd;return!!(t&&i&&e)&&this._areCoordsInSelection(e,t,i)}isCellInSelection(e,t){var i=this._model.finalSelectionStart,r=this._model.finalSelectionEnd;return!(!i||!r)&&this._areCoordsInSelection([e,t],i,r)}_areCoordsInSelection(e,t,i){return e[1]>t[1]&&e[1]=t[0]&&e[0]=t[0]}_selectWordAtCursor(e,t){var i=null==(i=null==(i=this._linkifier.currentLink)?void 0:i.link)?void 0:i.range;return i?(this._model.selectionStart=[i.start.x-1,i.start.y-1],this._model.selectionStartLength=(0,f.getRangeLength)(i,this._bufferService.cols),!(this._model.selectionEnd=void 0)):!!(i=this._getMouseBufferCoords(e))&&(this._selectWordAt(i,t),!(this._model.selectionEnd=void 0))}selectAll(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()}selectLines(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()}_onTrim(e){this._model.onTrim(e)&&this.refresh()}_getMouseBufferCoords(e){e=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(e)return e[0]--,e[1]--,e[1]+=this._bufferService.buffer.ydisp,e}_getMouseEventScrollAmount(e){let t=(0,h.getCoordsRelativeToElement)(this._coreBrowserService.window,e,this._screenElement)[1];e=this._renderService.dimensions.canvasHeight;return 0<=t&&t<=e?0:(t>e&&(t-=e),t=Math.min(Math.max(t,-50),50),(t/=50)/Math.abs(t)+Math.round(14*t))}shouldForceSelection(e){return a.isMac?e.altKey&&this._optionsService.rawOptions.macOptionClickForcesSelection:e.shiftKey}onMouseDown(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._onIncrementalClick(e):1===e.detail?this._onSingleClick(e):2===e.detail?this._onDoubleClick(e):3===e.detail&&this._onTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}}_addMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=this._coreBrowserService.window.setInterval(()=>this._dragScroll(),50)}_removeMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),this._coreBrowserService.window.clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0}_onIncrementalClick(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))}_onSingleClick(e){this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),this._model.selectionStart&&(this._model.selectionEnd=void 0,e=this._bufferService.buffer.lines.get(this._model.selectionStart[1]))&&e.length!==this._model.selectionStart[0]&&0===e.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}_onDoubleClick(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)}_onTripleClick(e){e=this._getMouseBufferCoords(e);e&&(this._activeSelectionMode=2,this._selectLineAt(e[1]))}shouldColumnSelect(e){return e.altKey&&!(a.isMac&&this._optionsService.rawOptions.macOptionClickForcesSelection)}_onMouseMove(e){if(e.stopImmediatePropagation(),this._model.selectionStart){var t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),this._model.selectionEnd){2===this._activeSelectionMode?this._model.selectionEnd[1]this._onTrim(e))}_convertViewportColToCharacterIndex(t,i){let r=i[0];for(let e=0;i[0]>=e;e++){var s=t.loadCell(e,this._workCell).getChars().length;0===this._workCell.getWidth()?r--:1=this._bufferService.cols)){var d=this._bufferService.buffer,u=d.lines.get(c[1]);if(u){var f=d.translateBufferLineToString(c[1],!1);let r=this._convertViewportColToCharacterIndex(u,c),s=r;var v=c[0]-r;let n=0,o=0,a=0,h=0;if(" "===f.charAt(r)){for(;0this._bufferService.cols;)i.length-=this._bufferService.cols,e++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?i.start:i.start+i.length,e]}}_isCharWordSeparator(e){return 0!==e.getWidth()&&0<=this._optionsService.rawOptions.wordSeparator.indexOf(e.getChars())}_selectLineAt(e){var e=this._bufferService.buffer.getWrappedRangeForLine(e),t={start:{x:0,y:e.first},end:{x:this._bufferService.cols-1,y:e.last}};this._model.selectionStart=[0,e.first],this._model.selectionEnd=void 0,this._model.selectionStartLength=(0,f.getRangeLength)(t,this._bufferService.cols)}},i=r([s(3,o.IBufferService),s(4,o.ICoreService),s(5,n.IMouseService),s(6,o.IOptionsService),s(7,n.IRenderService),s(8,n.ICoreBrowserService)],i);t.SelectionService=i},4725:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ICharacterJoinerService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;i=i(8343);t.ICharSizeService=(0,i.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,i.createDecorator)("CoreBrowserService"),t.IMouseService=(0,i.createDecorator)("MouseService"),t.IRenderService=(0,i.createDecorator)("RenderService"),t.ISelectionService=(0,i.createDecorator)("SelectionService"),t.ICharacterJoinerService=(0,i.createDecorator)("CharacterJoinerService")},6349:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;let r=i(8460);t.CircularList=class{constructor(e){this._maxLength=e,this.onDeleteEmitter=new r.EventEmitter,this.onInsertEmitter=new r.EventEmitter,this.onTrimEmitter=new r.EventEmitter,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}get onDelete(){return this.onDeleteEmitter.event}get onInsert(){return this.onInsertEmitter.event}get onTrim(){return this.onTrimEmitter.event}get maxLength(){return this._maxLength}set maxLength(t){if(this._maxLength!==t){var i=new Array(t);for(let e=0;ethis._length)for(let e=this._length;e=t;e--)this._array[this._getCyclicIndex(e+r.length)]=this._array[this._getCyclicIndex(e)];for(let e=0;ethis._maxLength){let e=this._length+r.length-this._maxLength;this._startIndex+=e,this._length=this._maxLength,this.onTrimEmitter.fire(e)}else this._length+=r.length}trimStart(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)}shiftElements(t,i,r){if(!(i<=0)){if(t<0||t>=this._length)throw new Error("start argument out of range");if(t+r<0)throw new Error("Cannot shift elements in list beyond index 0");if(0this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(let e=0;e{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,i=5){if("object"!=typeof t)return t;var r,s=Array.isArray(t)?[]:{};for(r in t)s[r]=i<=1?t[r]:t[r]&&e(t[r],i-1);return s}},8055:(e,t)=>{var a,c,o,i;function s(e){e=e.toString(16);return e.length<2?"0"+e:e}function _(e,t){return e>24&255,s=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,l=_(c.relativeLuminance2(o,a,h),c.relativeLuminance2(r,s,n));for(;l>>0}function l(e,t,i){var r=e>>24&255,s=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,l=_(c.relativeLuminance2(o,a,h),c.relativeLuminance2(r,s,n));for(;l>>0}function r(e,t,i){e/=255,t/=255,i/=255;return.2126*(e<=.03928?e/12.92:Math.pow((.055+e)/1.055,2.4))+.7152*(t<=.03928?t/12.92:Math.pow((.055+t)/1.055,2.4))+.0722*(i<=.03928?i/12.92:Math.pow((.055+i)/1.055,2.4))}function n(e,t){var t=Math.round(255*t),[e,i,r]=o.toChannels(e.rgba);return{css:a.toCss(e,i,r,t),rgba:a.toRgba(e,i,r,t)}}Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=void 0,(i=a=t.channels||(t.channels={})).toCss=function(e,t,i,r){return void 0!==r?"#"+s(e)+s(t)+s(i)+s(r):"#"+s(e)+s(t)+s(i)},i.toRgba=function(e,t,i,r=255){return(e<<24|t<<16|i<<8|r)>>>0},(i=t.color||(t.color={})).blend=function(e,t){var i,r,s,n,o=(255&t.rgba)/255;return 1==o?{css:t.css,rgba:t.rgba}:(n=t.rgba>>16&255,i=t.rgba>>8&255,s=e.rgba>>24&255,r=e.rgba>>16&255,e=e.rgba>>8&255,t=s+Math.round(((t.rgba>>24&255)-s)*o),s=r+Math.round((n-r)*o),n=e+Math.round((i-e)*o),{css:a.toCss(t,s,n),rgba:a.toRgba(t,s,n)})},i.isOpaque=function(e){return 255==(255&e.rgba)},i.ensureContrastRatio=function(e,t,i){e=o.ensureContrastRatio(e.rgba,t.rgba,i);if(e)return o.toColor(e>>24&255,e>>16&255,e>>8&255)},i.opaque=function(e){var e=(255|e.rgba)>>>0,[t,i,r]=o.toChannels(e);return{css:a.toCss(t,i,r),rgba:e}},i.opacity=n,i.multiplyOpacity=function(e,t){return n(e,(255&e.rgba)*t/255)},i.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]},(t.css||(t.css={})).toColor=function(s){if(s.match(/#[0-9a-f]{3,8}/i))switch(s.length){case 4:{let e=parseInt(s.slice(1,2).repeat(2),16),t=parseInt(s.slice(2,3).repeat(2),16),i=parseInt(s.slice(3,4).repeat(2),16);return o.toColor(e,t,i)}case 5:{let e=parseInt(s.slice(1,2).repeat(2),16),t=parseInt(s.slice(2,3).repeat(2),16),i=parseInt(s.slice(3,4).repeat(2),16),r=parseInt(s.slice(4,5).repeat(2),16);return o.toColor(e,t,i,r)}case 7:return{css:s,rgba:(parseInt(s.slice(1),16)<<8|255)>>>0};case 9:return{css:s,rgba:parseInt(s.slice(1),16)>>>0}}let n=s.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);if(n){let e=parseInt(n[1]),t=parseInt(n[2]),i=parseInt(n[3]),r=Math.round(255*(void 0===n[5]?1:parseFloat(n[5])));return o.toColor(e,t,i,r)}throw new Error("css.toColor: Unsupported css format")},(i=c=t.rgb||(t.rgb={})).relativeLuminance=function(e){return r(e>>16&255,e>>8&255,255&e)},i.relativeLuminance2=r,(i=o=t.rgba||(t.rgba={})).ensureContrastRatio=function(r,s,n){let o=c.relativeLuminance(r>>8),e=c.relativeLuminance(s>>8);if(_(o,e)>8));if(i_(o,c.relativeLuminance(e>>8))?t:e}return t}var t=l(r,s,n),i=_(o,c.relativeLuminance(t>>8));if(i_(o,c.relativeLuminance(e>>8))?t:e}return t}},i.reduceLuminance=h,i.increaseLuminance=l,i.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},i.toColor=function(e,t,i,r){return{css:a.toCss(e,t,i,r),rgba:a.toRgba(e,t,i,r)}},t.toPaddedHex=s,t.contrastRatio=_},8969:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;let r=i(844),s=i(2585),n=i(4348),o=i(7866),a=i(744),h=i(7302),l=i(6975),c=i(8460),_=i(1753),d=i(3730),u=i(1480),f=i(7994),v=i(9282),g=i(5435),p=i(5981),S=i(2660),m=!1;class C extends r.Disposable{constructor(e){super(),this._onBinary=new c.EventEmitter,this._onData=new c.EventEmitter,this._onLineFeed=new c.EventEmitter,this._onResize=new c.EventEmitter,this._onScroll=new c.EventEmitter,this._onWriteParsed=new c.EventEmitter,this._instantiationService=new n.InstantiationService,this.optionsService=new h.OptionsService(e),this._instantiationService.setService(s.IOptionsService,this.optionsService),this._bufferService=this.register(this._instantiationService.createInstance(a.BufferService)),this._instantiationService.setService(s.IBufferService,this._bufferService),this._logService=this._instantiationService.createInstance(o.LogService),this._instantiationService.setService(s.ILogService,this._logService),this.coreService=this.register(this._instantiationService.createInstance(l.CoreService,()=>this.scrollToBottom())),this._instantiationService.setService(s.ICoreService,this.coreService),this.coreMouseService=this._instantiationService.createInstance(_.CoreMouseService),this._instantiationService.setService(s.ICoreMouseService,this.coreMouseService),this._dirtyRowService=this._instantiationService.createInstance(d.DirtyRowService),this._instantiationService.setService(s.IDirtyRowService,this._dirtyRowService),this.unicodeService=this._instantiationService.createInstance(u.UnicodeService),this._instantiationService.setService(s.IUnicodeService,this.unicodeService),this._charsetService=this._instantiationService.createInstance(f.CharsetService),this._instantiationService.setService(s.ICharsetService,this._charsetService),this._oscLinkService=this._instantiationService.createInstance(S.OscLinkService),this._instantiationService.setService(s.IOscLinkService,this._oscLinkService),this._inputHandler=new g.InputHandler(this._bufferService,this._charsetService,this.coreService,this._dirtyRowService,this._logService,this.optionsService,this._oscLinkService,this.coreMouseService,this.unicodeService),this.register((0,c.forwardEvent)(this._inputHandler.onLineFeed,this._onLineFeed)),this.register(this._inputHandler),this.register((0,c.forwardEvent)(this._bufferService.onResize,this._onResize)),this.register((0,c.forwardEvent)(this.coreService.onData,this._onData)),this.register((0,c.forwardEvent)(this.coreService.onBinary,this._onBinary)),this.register(this.optionsService.onOptionChange(e=>this._updateOptions(e))),this.register(this._bufferService.onScroll(e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)})),this.register(this._inputHandler.onScroll(e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)})),this._writeBuffer=new p.WriteBuffer((e,t)=>this._inputHandler.parse(e,t)),this.register((0,c.forwardEvent)(this._writeBuffer.onWriteParsed,this._onWriteParsed))}get onBinary(){return this._onBinary.event}get onData(){return this._onData.event}get onLineFeed(){return this._onLineFeed.event}get onResize(){return this._onResize.event}get onWriteParsed(){return this._onWriteParsed.event}get onScroll(){return this._onScrollApi||(this._onScrollApi=new c.EventEmitter,this.register(this._onScroll.event(e=>{var t;null!=(t=this._onScrollApi)&&t.fire(e.position)}))),this._onScrollApi.event}get cols(){return this._bufferService.cols}get rows(){return this._bufferService.rows}get buffers(){return this._bufferService.buffers}get options(){return this.optionsService.options}set options(e){for(var t in e)this.optionsService.options[t]=e[t]}dispose(){var e;this._isDisposed||(super.dispose(),null!=(e=this._windowsMode)&&e.dispose(),this._windowsMode=void 0)}write(e,t){this._writeBuffer.write(e,t)}writeSync(e,t){this._logService.logLevel<=s.LogLevelEnum.WARN&&!m&&(this._logService.warn("writeSync is unreliable and will be removed soon."),m=!0),this._writeBuffer.writeSync(e,t)}resize(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,a.MINIMUM_COLS),t=Math.max(t,a.MINIMUM_ROWS),this._bufferService.resize(e,t))}scroll(e,t=!1){this._bufferService.scroll(e,t)}scrollLines(e,t,i){this._bufferService.scrollLines(e,t,i)}scrollPages(e){this._bufferService.scrollPages(e)}scrollToTop(){this._bufferService.scrollToTop()}scrollToBottom(){this._bufferService.scrollToBottom()}scrollToLine(e){this._bufferService.scrollToLine(e)}registerEscHandler(e,t){return this._inputHandler.registerEscHandler(e,t)}registerDcsHandler(e,t){return this._inputHandler.registerDcsHandler(e,t)}registerCsiHandler(e,t){return this._inputHandler.registerCsiHandler(e,t)}registerOscHandler(e,t){return this._inputHandler.registerOscHandler(e,t)}_setup(){this.optionsService.rawOptions.windowsMode&&this._enableWindowsMode()}reset(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()}_updateOptions(e){var t;switch(e){case"scrollback":this.buffers.resize(this.cols,this.rows);break;case"windowsMode":this.optionsService.rawOptions.windowsMode?this._enableWindowsMode():(null!=(t=this._windowsMode)&&t.dispose(),this._windowsMode=void 0)}}_enableWindowsMode(){if(!this._windowsMode){let t=[];t.push(this.onLineFeed(v.updateWindowsModeWrappedState.bind(null,this._bufferService))),t.push(this.registerCsiHandler({final:"H"},()=>((0,v.updateWindowsModeWrappedState)(this._bufferService),!1))),this._windowsMode={dispose:()=>{for(var e of t)e.dispose()}}}}}t.CoreTerminal=C},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=t=>(this._listeners.push(t),{dispose:()=>{if(!this._disposed)for(let e=0;et.fire(e))}},5435:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;let d=i(2584),c=i(7116),_=i(2015),r=i(844),u=i(482),f=i(8437),v=i(8460),g=i(643),p=i(511),n=i(3734),a=i(2585),S=i(6242),m=i(6351),s=i(5941),o={"(":0,")":1,"*":2,"+":3,"-":1,".":2},h=131072;function l(e,t){if(24this._activeBuffer=e.activeBuffer)),this._parser.setCsiHandlerFallback((e,t)=>{this._logService.debug("Unknown CSI code: ",{identifier:this._parser.identToString(e),params:t.toArray()})}),this._parser.setEscHandlerFallback(e=>{this._logService.debug("Unknown ESC code: ",{identifier:this._parser.identToString(e)})}),this._parser.setExecuteHandlerFallback(e=>{this._logService.debug("Unknown EXECUTE code: ",{code:e})}),this._parser.setOscHandlerFallback((e,t,i)=>{this._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:i})}),this._parser.setDcsHandlerFallback((e,t,i)=>{"HOOK"===t&&(i=i.toArray()),this._logService.debug("Unknown DCS code: ",{identifier:this._parser.identToString(e),action:t,payload:i})}),this._parser.setPrintHandler((e,t,i)=>this.print(e,t,i)),this._parser.registerCsiHandler({final:"@"},e=>this.insertChars(e)),this._parser.registerCsiHandler({intermediates:" ",final:"@"},e=>this.scrollLeft(e)),this._parser.registerCsiHandler({final:"A"},e=>this.cursorUp(e)),this._parser.registerCsiHandler({intermediates:" ",final:"A"},e=>this.scrollRight(e)),this._parser.registerCsiHandler({final:"B"},e=>this.cursorDown(e)),this._parser.registerCsiHandler({final:"C"},e=>this.cursorForward(e)),this._parser.registerCsiHandler({final:"D"},e=>this.cursorBackward(e)),this._parser.registerCsiHandler({final:"E"},e=>this.cursorNextLine(e)),this._parser.registerCsiHandler({final:"F"},e=>this.cursorPrecedingLine(e)),this._parser.registerCsiHandler({final:"G"},e=>this.cursorCharAbsolute(e)),this._parser.registerCsiHandler({final:"H"},e=>this.cursorPosition(e)),this._parser.registerCsiHandler({final:"I"},e=>this.cursorForwardTab(e)),this._parser.registerCsiHandler({final:"J"},e=>this.eraseInDisplay(e,!1)),this._parser.registerCsiHandler({prefix:"?",final:"J"},e=>this.eraseInDisplay(e,!0)),this._parser.registerCsiHandler({final:"K"},e=>this.eraseInLine(e,!1)),this._parser.registerCsiHandler({prefix:"?",final:"K"},e=>this.eraseInLine(e,!0)),this._parser.registerCsiHandler({final:"L"},e=>this.insertLines(e)),this._parser.registerCsiHandler({final:"M"},e=>this.deleteLines(e)),this._parser.registerCsiHandler({final:"P"},e=>this.deleteChars(e)),this._parser.registerCsiHandler({final:"S"},e=>this.scrollUp(e)),this._parser.registerCsiHandler({final:"T"},e=>this.scrollDown(e)),this._parser.registerCsiHandler({final:"X"},e=>this.eraseChars(e)),this._parser.registerCsiHandler({final:"Z"},e=>this.cursorBackwardTab(e)),this._parser.registerCsiHandler({final:"`"},e=>this.charPosAbsolute(e)),this._parser.registerCsiHandler({final:"a"},e=>this.hPositionRelative(e)),this._parser.registerCsiHandler({final:"b"},e=>this.repeatPrecedingCharacter(e)),this._parser.registerCsiHandler({final:"c"},e=>this.sendDeviceAttributesPrimary(e)),this._parser.registerCsiHandler({prefix:">",final:"c"},e=>this.sendDeviceAttributesSecondary(e)),this._parser.registerCsiHandler({final:"d"},e=>this.linePosAbsolute(e)),this._parser.registerCsiHandler({final:"e"},e=>this.vPositionRelative(e)),this._parser.registerCsiHandler({final:"f"},e=>this.hVPosition(e)),this._parser.registerCsiHandler({final:"g"},e=>this.tabClear(e)),this._parser.registerCsiHandler({final:"h"},e=>this.setMode(e)),this._parser.registerCsiHandler({prefix:"?",final:"h"},e=>this.setModePrivate(e)),this._parser.registerCsiHandler({final:"l"},e=>this.resetMode(e)),this._parser.registerCsiHandler({prefix:"?",final:"l"},e=>this.resetModePrivate(e)),this._parser.registerCsiHandler({final:"m"},e=>this.charAttributes(e)),this._parser.registerCsiHandler({final:"n"},e=>this.deviceStatus(e)),this._parser.registerCsiHandler({prefix:"?",final:"n"},e=>this.deviceStatusPrivate(e)),this._parser.registerCsiHandler({intermediates:"!",final:"p"},e=>this.softReset(e)),this._parser.registerCsiHandler({intermediates:" ",final:"q"},e=>this.setCursorStyle(e)),this._parser.registerCsiHandler({final:"r"},e=>this.setScrollRegion(e)),this._parser.registerCsiHandler({final:"s"},e=>this.saveCursor(e)),this._parser.registerCsiHandler({final:"t"},e=>this.windowOptions(e)),this._parser.registerCsiHandler({final:"u"},e=>this.restoreCursor(e)),this._parser.registerCsiHandler({intermediates:"'",final:"}"},e=>this.insertColumns(e)),this._parser.registerCsiHandler({intermediates:"'",final:"~"},e=>this.deleteColumns(e)),this._parser.registerCsiHandler({intermediates:'"',final:"q"},e=>this.selectProtected(e)),this._parser.registerCsiHandler({intermediates:"$",final:"p"},e=>this.requestMode(e,!0)),this._parser.registerCsiHandler({prefix:"?",intermediates:"$",final:"p"},e=>this.requestMode(e,!1)),this._parser.setExecuteHandler(d.C0.BEL,()=>this.bell()),this._parser.setExecuteHandler(d.C0.LF,()=>this.lineFeed()),this._parser.setExecuteHandler(d.C0.VT,()=>this.lineFeed()),this._parser.setExecuteHandler(d.C0.FF,()=>this.lineFeed()),this._parser.setExecuteHandler(d.C0.CR,()=>this.carriageReturn()),this._parser.setExecuteHandler(d.C0.BS,()=>this.backspace()),this._parser.setExecuteHandler(d.C0.HT,()=>this.tab()),this._parser.setExecuteHandler(d.C0.SO,()=>this.shiftOut()),this._parser.setExecuteHandler(d.C0.SI,()=>this.shiftIn()),this._parser.setExecuteHandler(d.C1.IND,()=>this.index()),this._parser.setExecuteHandler(d.C1.NEL,()=>this.nextLine()),this._parser.setExecuteHandler(d.C1.HTS,()=>this.tabSet()),this._parser.registerOscHandler(0,new S.OscHandler(e=>(this.setTitle(e),this.setIconName(e),!0))),this._parser.registerOscHandler(1,new S.OscHandler(e=>this.setIconName(e))),this._parser.registerOscHandler(2,new S.OscHandler(e=>this.setTitle(e))),this._parser.registerOscHandler(4,new S.OscHandler(e=>this.setOrReportIndexedColor(e))),this._parser.registerOscHandler(8,new S.OscHandler(e=>this.setHyperlink(e))),this._parser.registerOscHandler(10,new S.OscHandler(e=>this.setOrReportFgColor(e))),this._parser.registerOscHandler(11,new S.OscHandler(e=>this.setOrReportBgColor(e))),this._parser.registerOscHandler(12,new S.OscHandler(e=>this.setOrReportCursorColor(e))),this._parser.registerOscHandler(104,new S.OscHandler(e=>this.restoreIndexedColor(e))),this._parser.registerOscHandler(110,new S.OscHandler(e=>this.restoreFgColor(e))),this._parser.registerOscHandler(111,new S.OscHandler(e=>this.restoreBgColor(e))),this._parser.registerOscHandler(112,new S.OscHandler(e=>this.restoreCursorColor(e))),this._parser.registerEscHandler({final:"7"},()=>this.saveCursor()),this._parser.registerEscHandler({final:"8"},()=>this.restoreCursor()),this._parser.registerEscHandler({final:"D"},()=>this.index()),this._parser.registerEscHandler({final:"E"},()=>this.nextLine()),this._parser.registerEscHandler({final:"H"},()=>this.tabSet()),this._parser.registerEscHandler({final:"M"},()=>this.reverseIndex()),this._parser.registerEscHandler({final:"="},()=>this.keypadApplicationMode()),this._parser.registerEscHandler({final:">"},()=>this.keypadNumericMode()),this._parser.registerEscHandler({final:"c"},()=>this.fullReset()),this._parser.registerEscHandler({final:"n"},()=>this.setgLevel(2)),this._parser.registerEscHandler({final:"o"},()=>this.setgLevel(3)),this._parser.registerEscHandler({final:"|"},()=>this.setgLevel(3)),this._parser.registerEscHandler({final:"}"},()=>this.setgLevel(2)),this._parser.registerEscHandler({final:"~"},()=>this.setgLevel(1)),this._parser.registerEscHandler({intermediates:"%",final:"@"},()=>this.selectDefaultCharset()),this._parser.registerEscHandler({intermediates:"%",final:"G"},()=>this.selectDefaultCharset());for(let e in c.CHARSETS)this._parser.registerEscHandler({intermediates:"(",final:e},()=>this.selectCharset("("+e)),this._parser.registerEscHandler({intermediates:")",final:e},()=>this.selectCharset(")"+e)),this._parser.registerEscHandler({intermediates:"*",final:e},()=>this.selectCharset("*"+e)),this._parser.registerEscHandler({intermediates:"+",final:e},()=>this.selectCharset("+"+e)),this._parser.registerEscHandler({intermediates:"-",final:e},()=>this.selectCharset("-"+e)),this._parser.registerEscHandler({intermediates:".",final:e},()=>this.selectCharset("."+e)),this._parser.registerEscHandler({intermediates:"/",final:e},()=>this.selectCharset("/"+e));this._parser.registerEscHandler({intermediates:"#",final:"8"},()=>this.screenAlignmentPattern()),this._parser.setErrorHandler(e=>(this._logService.error("Parsing error: ",e),e)),this._parser.registerDcsHandler({intermediates:"$",final:"q"},new m.DcsHandler((e,t)=>this.requestStatusString(e,t)))}getAttrData(){return this._curAttrData}get onRequestBell(){return this._onRequestBell.event}get onRequestRefreshRows(){return this._onRequestRefreshRows.event}get onRequestReset(){return this._onRequestReset.event}get onRequestSendFocus(){return this._onRequestSendFocus.event}get onRequestSyncScrollBar(){return this._onRequestSyncScrollBar.event}get onRequestWindowsOptionsReport(){return this._onRequestWindowsOptionsReport.event}get onA11yChar(){return this._onA11yChar.event}get onA11yTab(){return this._onA11yTab.event}get onCursorMove(){return this._onCursorMove.event}get onLineFeed(){return this._onLineFeed.event}get onScroll(){return this._onScroll.event}get onTitleChange(){return this._onTitleChange.event}get onColor(){return this._onColor.event}dispose(){super.dispose()}_preserveStack(e,t,i,r){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=i,this._parseStack.position=r}_logSlowResolvingAsync(e){this._logService.logLevel<=a.LogLevelEnum.WARN&&Promise.race([e,new Promise((e,t)=>setTimeout(()=>t("#SLOW_TIMEOUT"),5e3))]).catch(e=>{if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")})}parse(r,e){let s,n=this._activeBuffer.x,o=this._activeBuffer.y,t=0,i=this._parseStack.paused;if(i){if(s=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,e))return this._logSlowResolvingAsync(s),s;n=this._parseStack.cursorStartX,o=this._parseStack.cursorStartY,this._parseStack.paused=!1,r.length>h&&(t=this._parseStack.position+h)}if(this._logService.logLevel<=a.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof r?` "${r}"`:` "${Array.prototype.map.call(r,e=>String.fromCharCode(e)).join("")}"`),"string"==typeof r?r.split("").map(e=>e.charCodeAt(0)):r),this._parseBuffer.lengthh)for(let i=t;i=h)if(l){for(;this._activeBuffer.x=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),d=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)}else if(this._activeBuffer.x=h-1,2===n)continue;if(c&&(d.insertCells(this._activeBuffer.x,n,this._activeBuffer.getNullCell(_),_),2===d.getWidth(h-1))&&d.setCellFromCodePoint(h-1,g.NULL_CELL_CODE,g.NULL_CELL_WIDTH,_.fg,_.bg,_.extended),d.setCellFromCodePoint(this._activeBuffer.x++,s,n,_.fg,_.bg,_.extended),0!l(e.params[0],this._optionsService.rawOptions.windowOptions)||t(e))}registerDcsHandler(e,t){return this._parser.registerDcsHandler(e,new m.DcsHandler(t))}registerEscHandler(e,t){return this._parser.registerEscHandler(e,t)}registerOscHandler(e,t){return this._parser.registerOscHandler(e,new S.OscHandler(t))}bell(){return this._onRequestBell.fire(),!0}lineFeed(){return this._dirtyRowService.markDirty(this._activeBuffer.y),this._optionsService.rawOptions.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowService.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0}carriageReturn(){return!(this._activeBuffer.x=0)}backspace(){var e;if(this._coreService.decPrivateModes.reverseWraparound){if(this._restrictCursor(this._bufferService.cols),0this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&null!=(e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y))&&e.isWrapped){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;let e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);e.hasWidth(this._activeBuffer.x)&&!e.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}this._restrictCursor()}else this._restrictCursor(),0=this._bufferService.cols||(e=this._activeBuffer.x,this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.rawOptions.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e)),!0}shiftOut(){return this._charsetService.setgLevel(1),!0}shiftIn(){return this._charsetService.setgLevel(0),!0}_restrictCursor(e=this._bufferService.cols-1){this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowService.markDirty(this._activeBuffer.y)}_setCursor(e,t){this._dirtyRowService.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowService.markDirty(this._activeBuffer.y)}_moveCursor(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)}cursorUp(e){var t=this._activeBuffer.y-this._activeBuffer.scrollTop;return 0<=t?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0}cursorDown(e){var t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return 0<=t?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0}cursorForward(e){return this._moveCursor(e.params[0]||1,0),!0}cursorBackward(e){return this._moveCursor(-(e.params[0]||1),0),!0}cursorNextLine(e){return this.cursorDown(e),!(this._activeBuffer.x=0)}cursorPrecedingLine(e){return this.cursorUp(e),!(this._activeBuffer.x=0)}cursorCharAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}cursorPosition(e){return this._setCursor(2<=e.length?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0}charPosAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}hPositionRelative(e){return this._moveCursor(e.params[0]||1,0),!0}linePosAbsolute(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0}vPositionRelative(e){return this._moveCursor(0,e.params[0]||1),!0}hVPosition(e){return this.cursorPosition(e),!0}tabClear(e){e=e.params[0];return 0===e?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===e&&(this._activeBuffer.tabs={}),!0}cursorForwardTab(t){if(!(this._activeBuffer.x>=this._bufferService.cols)){let e=t.params[0]||1;for(;e--;)this._activeBuffer.x=this._activeBuffer.nextStop()}return!0}cursorBackwardTab(t){if(!(this._activeBuffer.x>=this._bufferService.cols)){let e=t.params[0]||1;for(;e--;)this._activeBuffer.x=this._activeBuffer.prevStop()}return!0}selectProtected(e){e=e.params[0];return 1===e&&(this._curAttrData.bg|=536870912),2!==e&&0!==e||(this._curAttrData.bg&=-536870913),!0}_eraseInBufferLine(e,t,i,r=!1,s=!1){e=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);e.replaceCells(t,i,this._activeBuffer.getNullCell(this._eraseAttrData()),this._eraseAttrData(),s),r&&(e.isWrapped=!1)}_resetBufferLine(e,t=!1){var i=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);i.fill(this._activeBuffer.getNullCell(this._eraseAttrData()),t),this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase+e),i.isWrapped=!1}eraseInDisplay(e,t=!1){let i;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(i=this._activeBuffer.y,this._dirtyRowService.markDirty(i),this._eraseInBufferLine(i++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);i=this._bufferService.cols&&(this._activeBuffer.lines.get(i+1).isWrapped=!1);i--;)this._resetBufferLine(i,t);this._dirtyRowService.markDirty(0);break;case 2:for(i=this._bufferService.rows,this._dirtyRowService.markDirty(i-1);i--;)this._resetBufferLine(i,t);this._dirtyRowService.markDirty(0);break;case 3:let e=this._activeBuffer.lines.length-this._bufferService.rows;0this._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.y0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(d.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(d.C0.ESC+"[>83;40003;0c")),!0}_is(e){return 0===(this._optionsService.rawOptions.termName+"").indexOf(e)}setMode(t){for(let e=0;ee?1:2,e=e.params[0],_=e,a=t?2===e?3:4===e?c(n.modes.insertMode):12===e?4:20===e?c(l.convertEol):0:1===e?c(i.applicationCursorKeys):3===e?l.windowOptions.setWinLines?80===a?2:132===a?1:0:0:6===e?c(i.origin):7===e?c(i.wraparound):8===e?3:9===e?"X10"===r?1:2:12===e?c(l.cursorBlink):25===e?c(!n.isCursorHidden):45===e?c(i.reverseWraparound):66===e?c(i.applicationKeypad):1e3===e?"VT200"===r?1:2:1002===e?"DRAG"===r?1:2:1003===e?"ANY"===r?1:2:1004===e?c(i.sendFocus):1005===e?4:1006===e?"SGR"===s?1:2:1015===e?4:1016===e?"SGR_PIXELS"===s?1:2:1048===e?1:47===e||1047===e||1049===e?o===h?1:2:2004===e?c(i.bracketedPasteMode):0;return n.triggerDataEvent(d.C0.ESC+`[${t?"":"?"}${_};${a}$y`),!0}_updateAttrColor(e,t,i,r,s){return 2===t?e=(e=(e|50331648)&-16777216)|n.AttributeData.fromColorRGB([i,r,s]):5===t&&(e=e&-50331904|(33554432|255&i)),e}_extractColor(i,r,e){var s=[0,0,-1,0,0,0];let n=0,o=0;do{if(s[o+n]=i.params[r+o],i.hasSubParams(r+o)){let e=i.getSubParams(r+o),t=0;for(;5===s[1]&&(n=1),s[o+t+1+n]=e[t],++tthis._bufferService.rows||0===i?this._bufferService.rows:i)>t&&(this._activeBuffer.scrollTop=t-1,this._activeBuffer.scrollBottom=i-1,this._setCursor(0,0)),!0}windowOptions(e){if(l(e.params[0],this._optionsService.rawOptions.windowOptions)){var t=1e.startsWith("id="));return-1!==r&&(i=e[r].slice(3)||void 0),this._curAttrData.extended=this._curAttrData.extended.clone(),this._currentLinkId=this._oscLinkService.registerLink({id:i,uri:t}),this._curAttrData.extended.urlId=this._currentLinkId,this._curAttrData.updateExtended(),!0}_finishHyperlink(){return this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=0,this._curAttrData.updateExtended(),!(this._currentLinkId=void 0)}_setOrReportSpecialColor(e,t){var i,r=e.split(";");for(let e=0;e=this._specialColors.length);++e,++t)"?"===r[e]?this._onColor.fire([{type:0,index:this._specialColors[t]}]):(i=(0,s.parseColor)(r[e]))&&this._onColor.fire([{type:1,index:this._specialColors[t],color:i}]);return!0}setOrReportFgColor(e){return this._setOrReportSpecialColor(e,0)}setOrReportBgColor(e){return this._setOrReportSpecialColor(e,1)}setOrReportCursorColor(e){return this._setOrReportSpecialColor(e,2)}restoreIndexedColor(e){if(e){var t,i=[],r=e.split(";");for(let e=0;e=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0}tabSet(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0}reverseIndex(){var e;return this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop?(e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop,this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)):(this._activeBuffer.y--,this._restrictCursor()),!0}fullReset(){return this._parser.reset(),this._onRequestReset.fire(),!0}reset(){this._curAttrData=f.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=f.DEFAULT_ATTR_DATA.clone()}_eraseAttrData(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal}setgLevel(e){return this._charsetService.setgLevel(e),!0}screenAlignmentPattern(){var t=new p.CellData;t.content=1<<22|"E".charCodeAt(0),t.fg=this._curAttrData.fg,t.bg=this._curAttrData.bg,this._setCursor(0,0);for(let e=0;e{function i(e){for(var t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(var e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){e=this._disposables.indexOf(e);-1!==e&&this._disposables.splice(e,1)}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}},1505:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FourKeyMap=t.TwoKeyMap=void 0;class n{constructor(){this._data={}}set(e,t,i){this._data[e]||(this._data[e]={}),this._data[e][t]=i}get(e,t){return this._data[e]?this._data[e][t]:void 0}clear(){this._data={}}}t.TwoKeyMap=n,t.FourKeyMap=class{constructor(){this._data=new n}set(e,t,i,r,s){this._data.get(e,t)||this._data.set(e,t,new n),this._data.get(e,t).set(i,r,s)}get(e,t,i,r){return null==(e=this._data.get(e,t))?void 0:e.get(i,r)}clear(){this._data.clear()}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.isSafari=t.isLegacyEdge=t.isFirefox=void 0;var i="undefined"==typeof navigator,r=i?"node":navigator.userAgent,i=i?"node":navigator.platform;t.isFirefox=r.includes("Firefox"),t.isLegacyEdge=r.includes("Edge"),t.isSafari=/^((?!chrome|android).)*safari/i.test(r),t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(i),t.isIpad="iPad"===i,t.isIphone="iPhone"===i,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(i),t.isLinux=0<=i.indexOf("Linux")},6106:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SortedList=void 0;let i=0;t.SortedList=class{constructor(e){this._getKey=e,this._array=[]}clear(){this._array.length=0}insert(e){0!==this._array.length?(i=this._search(this._getKey(e),0,this._array.length-1),this._array.splice(i,0,e)):this._array.push(e)}delete(e){if(0!==this._array.length){var t=this._getKey(e);if(void 0!==t&&-1!==(i=this._search(t,0,this._array.length-1))&&this._getKey(this._array[i])===t)do{if(this._array[i]===e)return this._array.splice(i,1),!0}while(++i=this._array.length)&&this._getKey(this._array[i])===e)for(;yield this._array[i],++i=this._array.length)&&this._getKey(this._array[i])===e)for(;t(this._array[i]),++i{function s(t,i,r=0,s=t.length){if(!(r>=t.length)){s=t.length<=s?t.length:(t.length+s)%t.length;for(let e=r=(t.length+r)%t.length;e{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;let r=i(643);t.updateWindowsModeWrappedState=function(e){var t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),t=null==t?void 0:t.get(e.cols-1),e=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);e&&t&&(e.isWrapped=t[r.CHAR_DATA_CODE_INDEX]!==r.NULL_CELL_CODE&&t[r.CHAR_DATA_CODE_INDEX]!==r.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;t.AttributeData=class r{constructor(){this.fg=0,this.bg=0,this.extended=new i}static toColorRGB(e){return[e>>>16&255,e>>>8&255,255&e]}static fromColorRGB(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]}clone(){var e=new r;return e.fg=this.fg,e.bg=this.bg,e.extended=this.extended.clone(),e}isInverse(){return 67108864&this.fg}isBold(){return 134217728&this.fg}isUnderline(){return this.hasExtendedAttrs()&&0!==this.extended.underlineStyle?1:268435456&this.fg}isBlink(){return 536870912&this.fg}isInvisible(){return 1073741824&this.fg}isItalic(){return 67108864&this.bg}isDim(){return 134217728&this.bg}isStrikethrough(){return 2147483648&this.fg}isProtected(){return 536870912&this.bg}getFgColorMode(){return 50331648&this.fg}getBgColorMode(){return 50331648&this.bg}isFgRGB(){return 50331648==(50331648&this.fg)}isBgRGB(){return 50331648==(50331648&this.bg)}isFgPalette(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)}isBgPalette(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)}isFgDefault(){return 0==(50331648&this.fg)}isBgDefault(){return 0==(50331648&this.bg)}isAttributeDefault(){return 0===this.fg&&0===this.bg}getFgColor(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}}getBgColor(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}}hasExtendedAttrs(){return 268435456&this.bg}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()}isUnderlineColorRGB(){return 268435456&this.bg&&~this.extended.underlineColor?50331648==(50331648&this.extended.underlineColor):this.isFgRGB()}isUnderlineColorPalette(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()}isUnderlineColorDefault(){return 268435456&this.bg&&~this.extended.underlineColor?0==(50331648&this.extended.underlineColor):this.isFgDefault()}getUnderlineStyle(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0}};class i{constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}get ext(){return this._urlId?-469762049&this._ext|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(469762048&this._ext)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return 67108863&this._ext}set underlineColor(e){this._ext&=-67108864,this._ext|=67108863&e}get urlId(){return this._urlId}set urlId(e){this._urlId=e}clone(){return new i(this._ext,this._urlId)}isEmpty(){return 0===this.underlineStyle&&0===this._urlId}}t.ExtendedAttrs=i},9092:(e,i,t)=>{Object.defineProperty(i,"__esModule",{value:!0}),i.BufferStringIterator=i.Buffer=i.MAX_BUFFER_SIZE=void 0;let r=t(6349),S=t(8437),s=t(511),n=t(643),m=t(4634),o=t(4863),a=t(7116),h=t(3734);i.MAX_BUFFER_SIZE=4294967295,i.Buffer=class{constructor(e,t,i){this._hasScrollback=e,this._optionsService=t,this._bufferService=i,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.savedY=0,this.savedX=0,this.savedCurAttrData=S.DEFAULT_ATTR_DATA.clone(),this.savedCharset=a.DEFAULT_CHARSET,this.markers=[],this._nullCell=s.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]),this._whitespaceCell=s.CellData.fromCharData([0,n.WHITESPACE_CELL_CHAR,n.WHITESPACE_CELL_WIDTH,n.WHITESPACE_CELL_CODE]),this._isClearing=!1,this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new r.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}getNullCell(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new h.ExtendedAttrs),this._nullCell}getWhitespaceCell(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new h.ExtendedAttrs),this._whitespaceCell}getBlankLine(e,t){return new S.BufferLine(this._bufferService.cols,this.getNullCell(e),t)}get hasScrollback(){return this._hasScrollback&&this.lines.maxLength>this._rows}get isCursorInViewport(){var e=this.ybase+this.y-this.ydisp;return 0<=e&&ei.MAX_BUFFER_SIZE?i.MAX_BUFFER_SIZE:t:e}fillViewportRows(t){if(0===this.lines.length){void 0===t&&(t=S.DEFAULT_ATTR_DATA);let e=this._rows;for(;e--;)this.lines.push(this.getBlankLine(t))}}clear(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new r.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}resize(i,r){var s=this.getNullCell(S.DEFAULT_ATTR_DATA),n=this._getCorrectBufferLength(r);if(n>this.lines.maxLength&&(this.lines.maxLength=n),0r;e--)this.lines.length>r+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(ni))for(let e=0;ethis._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))}_reflowLarger(e,t){var i=(0,m.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(S.DEFAULT_ATTR_DATA));0=n&&ds+a){for(let e=o.newLines.length-1;0<=e;e--)this.lines.set(t--,o.newLines[e]);t++,i.push({index:s+1,amount:o.newLines.length}),a+=o.newLines.length,o=l[++n]}else this.lines.set(t,r[s--]);let t=0;for(let e=i.length-1;0<=e;e--)i[e].index+=t,this.lines.onInsertEmitter.fire(i[e]),t+=i[e].amount;var p=Math.max(0,e+c-this.lines.maxLength);0=this._cols?this._cols-1:e<0?0:e}nextStop(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e=this._cols?this._cols-1:e<0?0:e}clearMarkers(t){this._isClearing=!0;for(let e=0;e{t.line-=e,t.line<0&&t.dispose()})),t.register(this.lines.onInsert(e=>{t.line>=e.index&&(t.line+=e.amount)})),t.register(this.lines.onDelete(e=>{t.line>=e.index&&t.linee.index&&(t.line-=e.amount)})),t.register(t.onDispose(()=>this._removeMarker(t))),t}_removeMarker(e){this._isClearing||this.markers.splice(this.markers.indexOf(e),1)}iterator(e,t,i,r,s){return new l(this,e,t,i,r,s)}};class l{constructor(e,t,i=0,r=e.lines.length,s=0,n=0){this._buffer=e,this._trimRight=t,this._startIndex=i,this._endIndex=r,this._startOverscan=s,this._endOverscan=n,this._startIndex<0&&(this._startIndex=0),this._endIndex>this._buffer.lines.length&&(this._endIndex=this._buffer.lines.length),this._current=this._startIndex}hasNext(){return this._currentthis._endIndex+this._endOverscan&&(t.last=this._endIndex+this._endOverscan),t.first=Math.max(t.first,0),t.last=Math.min(t.last,this._buffer.lines.length);let i="";for(let e=t.first;e<=t.last;++e)i+=this._buffer.translateBufferLineToString(e,this._trimRight);return this._current=t.last+1,{range:t,content:i}}}i.BufferStringIterator=l},8437:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;let s=i(482),n=i(643),o=i(511),a=i(3734),r=(t.DEFAULT_ATTR_DATA=Object.freeze(new a.AttributeData),{startIndex:0});t.BufferLine=class h{constructor(t,e,i=!1){this.isWrapped=i,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*t);var r=e||o.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]);for(let e=0;e>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):i]}set(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],1>22}hasWidth(e){return 12582912&this._data[3*e+0]}getFg(e){return this._data[3*e+1]}getBg(e){return this._data[3*e+2]}hasContent(e){return 4194303&this._data[3*e+0]}getCodePoint(e){var t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t}isCombined(e){return 2097152&this._data[3*e+0]}getString(e){var t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,s.stringFromCodePoint)(2097151&t):""}isProtected(e){return 536870912&this._data[3*e+2]}loadCell(e,t){return r.startIndex=3*e,t.content=this._data[r.startIndex+0],t.fg=this._data[r.startIndex+1],t.bg=this._data[r.startIndex+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t}setCell(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg}setCellFromCodePoint(e,t,i,r,s,n){268435456&s&&(this._extendedAttrs[e]=n),this._data[3*e+0]=t|i<<22,this._data[3*e+1]=r,this._data[3*e+2]=s}addCodepointToCell(e,t){let i=this._data[3*e+0];2097152&i?this._combined[e]+=(0,s.stringFromCodePoint)(t):(i=2097151&i?(this._combined[e]=(0,s.stringFromCodePoint)(2097151&i)+(0,s.stringFromCodePoint)(t),-2097152&i|2097152):t|1<<22,this._data[3*e+0]=i)}insertCells(i,r,s,e){if((i%=this.length)&&2===this.getWidth(i-1)&&this.setCellFromCodePoint(i-1,0,1,(null==e?void 0:e.fg)||0,(null==e?void 0:e.bg)||0,(null==e?void 0:e.extended)||new a.ExtendedAttrs),rthis.length){var e=new Uint32Array(3*t);this.length&&(3*t>22);return 0}copyCellsFrom(i,r,s,e,t){var n=i._data;if(t)for(let t=e-1;0<=t;t--){for(let e=0;e<3;e++)this._data[3*(s+t)+e]=n[3*(r+t)+e];268435456&n[3*(r+t)+2]&&(this._extendedAttrs[s+t]=i._extendedAttrs[r+t])}else for(let t=0;t=r&&(this._combined[e-r+s]=i._combined[e])}}translateToString(e=!1,i=0,t=this.length){e&&(t=Math.min(t,this.getTrimmedLength()));let r="";for(;i>22||1}return r}}},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error(`Buffer range end (${e.end.x}, ${e.end.y}) cannot be before start (${e.start.x}, ${e.start.y})`);return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function u(e,t,i){var r;return t===e.length-1?e[t].getTrimmedLength():(r=!e[t].hasContent(i-1)&&1===e[t].getWidth(i-1),e=2===e[t+1].getWidth(0),r&&e?i-1:i)}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(r,h,l,s,c){let _=[];for(let i=0;i=i&&ss||0===d[e].getTrimmedLength());e--)t++;0u(i,t,r)).reduce((e,t)=>e+t);let n=0,o=0,a=0;for(;ah&&(n-=h,o++),2===i[o].getWidth(n-1)),h=(h&&n--,h?e-1:e);t.push(h),a+=h}return t},t.getWrappedLineTrimmedLength=u},5295:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;let r=i(9092),s=i(8460),n=i(844);class o extends n.Disposable{constructor(e,t){super(),this._optionsService=e,this._bufferService=t,this._onBufferActivate=this.register(new s.EventEmitter),this.reset()}get onBufferActivate(){return this._onBufferActivate.event}reset(){this._normal=new r.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new r.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()}get alt(){return this._alt}get active(){return this._activeBuffer}get normal(){return this._normal}activateNormalBuffer(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clearAllMarkers(),this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))}activateAltBuffer(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))}resize(e,t){this._normal.resize(e,t),this._alt.resize(e,t)}setupTabStops(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)}}t.BufferSet=o},511:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;let r=i(482),s=i(643),n=i(3734);class o extends n.AttributeData{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new n.ExtendedAttrs,this.combinedData=""}static fromCharData(e){var t=new o;return t.setFromCharData(e),t}isCombined(){return 2097152&this.content}getWidth(){return this.content>>22}getChars(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,r.stringFromCodePoint)(2097151&this.content):""}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content}setFromCharData(e){this.fg=e[s.CHAR_DATA_ATTR_INDEX],this.bg=0;let t=!1;var i,r;2{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_EXT=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=256,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.DEFAULT_EXT=0,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;let r=i(8460),s=i(844);class n extends s.Disposable{constructor(e){super(),this.line=e,this._id=n._nextId++,this.isDisposed=!1,this._onDispose=new r.EventEmitter}get id(){return this._id}get onDispose(){return this._onDispose.event}dispose(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),super.dispose())}}(t.Marker=n)._nextId=1},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"},t.CHARSETS.A={"#":"£"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"£","@":"¾","[":"ij","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS.R={"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"},t.CHARSETS.Y={"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"},t.CHARSETS.Z={"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS["="]={"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}},2584:(e,t)=>{var i,r;Object.defineProperty(t,"__esModule",{value:!0}),t.C1_ESCAPED=t.C1=t.C0=void 0,(r=i=t.C0||(t.C0={})).NUL="\0",r.SOH="",r.STX="",r.ETX="",r.EOT="",r.ENQ="",r.ACK="",r.BEL="",r.BS="\b",r.HT="\t",r.LF="\n",r.VT="\v",r.FF="\f",r.CR="\r",r.SO="",r.SI="",r.DLE="",r.DC1="",r.DC2="",r.DC3="",r.DC4="",r.NAK="",r.SYN="",r.ETB="",r.CAN="",r.EM="",r.SUB="",r.ESC="",r.FS="",r.GS="",r.RS="",r.US="",r.SP=" ",r.DEL="",(r=t.C1||(t.C1={})).PAD="€",r.HOP="",r.BPH="‚",r.NBH="ƒ",r.IND="„",r.NEL="…",r.SSA="†",r.ESA="‡",r.HTS="ˆ",r.HTJ="‰",r.VTS="Š",r.PLD="‹",r.PLU="Œ",r.RI="",r.SS2="Ž",r.SS3="",r.DCS="",r.PU1="‘",r.PU2="’",r.STS="“",r.CCH="”",r.MW="•",r.SPA="–",r.EPA="—",r.SOS="˜",r.SGCI="™",r.SCI="š",r.CSI="›",r.ST="œ",r.OSC="",r.PM="ž",r.APC="Ÿ",(t.C1_ESCAPED||(t.C1_ESCAPED={})).ST=i.ESC+"\\"},7399:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;let o=i(2584),a={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(i,e,t,r){var s={type:0,cancel:!1,key:void 0},n=(i.shiftKey?1:0)|(i.altKey?2:0)|(i.ctrlKey?4:0)|(i.metaKey?8:0);switch(i.keyCode){case 0:"UIKeyInputUpArrow"===i.key?s.key=e?o.C0.ESC+"OA":o.C0.ESC+"[A":"UIKeyInputLeftArrow"===i.key?s.key=e?o.C0.ESC+"OD":o.C0.ESC+"[D":"UIKeyInputRightArrow"===i.key?s.key=e?o.C0.ESC+"OC":o.C0.ESC+"[C":"UIKeyInputDownArrow"===i.key&&(s.key=e?o.C0.ESC+"OB":o.C0.ESC+"[B");break;case 8:i.altKey?s.key=o.C0.ESC+o.C0.DEL:s.key=o.C0.DEL;break;case 9:i.shiftKey?s.key=o.C0.ESC+"[Z":(s.key=o.C0.HT,s.cancel=!0);break;case 13:s.key=i.altKey?o.C0.ESC+o.C0.CR:o.C0.CR,s.cancel=!0;break;case 27:s.key=o.C0.ESC,i.altKey&&(s.key=o.C0.ESC+o.C0.ESC),s.cancel=!0;break;case 37:i.metaKey||(n?(s.key=o.C0.ESC+"[1;"+(1+n)+"D",s.key===o.C0.ESC+"[1;3D"&&(s.key=o.C0.ESC+(t?"b":"[1;5D"))):s.key=e?o.C0.ESC+"OD":o.C0.ESC+"[D");break;case 39:i.metaKey||(n?(s.key=o.C0.ESC+"[1;"+(1+n)+"C",s.key===o.C0.ESC+"[1;3C"&&(s.key=o.C0.ESC+(t?"f":"[1;5C"))):s.key=e?o.C0.ESC+"OC":o.C0.ESC+"[C");break;case 38:i.metaKey||(n?(s.key=o.C0.ESC+"[1;"+(1+n)+"A",t||s.key!==o.C0.ESC+"[1;3A"||(s.key=o.C0.ESC+"[1;5A")):s.key=e?o.C0.ESC+"OA":o.C0.ESC+"[A");break;case 40:i.metaKey||(n?(s.key=o.C0.ESC+"[1;"+(1+n)+"B",t||s.key!==o.C0.ESC+"[1;3B"||(s.key=o.C0.ESC+"[1;5B")):s.key=e?o.C0.ESC+"OB":o.C0.ESC+"[B");break;case 45:i.shiftKey||i.ctrlKey||(s.key=o.C0.ESC+"[2~");break;case 46:s.key=n?o.C0.ESC+"[3;"+(1+n)+"~":o.C0.ESC+"[3~";break;case 36:s.key=n?o.C0.ESC+"[1;"+(1+n)+"H":e?o.C0.ESC+"OH":o.C0.ESC+"[H";break;case 35:s.key=n?o.C0.ESC+"[1;"+(1+n)+"F":e?o.C0.ESC+"OF":o.C0.ESC+"[F";break;case 33:i.shiftKey?s.type=2:i.ctrlKey?s.key=o.C0.ESC+"[5;"+(1+n)+"~":s.key=o.C0.ESC+"[5~";break;case 34:i.shiftKey?s.type=3:i.ctrlKey?s.key=o.C0.ESC+"[6;"+(1+n)+"~":s.key=o.C0.ESC+"[6~";break;case 112:s.key=n?o.C0.ESC+"[1;"+(1+n)+"P":o.C0.ESC+"OP";break;case 113:s.key=n?o.C0.ESC+"[1;"+(1+n)+"Q":o.C0.ESC+"OQ";break;case 114:s.key=n?o.C0.ESC+"[1;"+(1+n)+"R":o.C0.ESC+"OR";break;case 115:s.key=n?o.C0.ESC+"[1;"+(1+n)+"S":o.C0.ESC+"OS";break;case 116:s.key=n?o.C0.ESC+"[15;"+(1+n)+"~":o.C0.ESC+"[15~";break;case 117:s.key=n?o.C0.ESC+"[17;"+(1+n)+"~":o.C0.ESC+"[17~";break;case 118:s.key=n?o.C0.ESC+"[18;"+(1+n)+"~":o.C0.ESC+"[18~";break;case 119:s.key=n?o.C0.ESC+"[19;"+(1+n)+"~":o.C0.ESC+"[19~";break;case 120:s.key=n?o.C0.ESC+"[20;"+(1+n)+"~":o.C0.ESC+"[20~";break;case 121:s.key=n?o.C0.ESC+"[21;"+(1+n)+"~":o.C0.ESC+"[21~";break;case 122:s.key=n?o.C0.ESC+"[23;"+(1+n)+"~":o.C0.ESC+"[23~";break;case 123:s.key=n?o.C0.ESC+"[24;"+(1+n)+"~":o.C0.ESC+"[24~";break;default:if(!i.ctrlKey||i.shiftKey||i.altKey||i.metaKey)if(t&&!r||!i.altKey||i.metaKey)!t||i.altKey||i.ctrlKey||i.shiftKey||!i.metaKey?i.key&&!i.ctrlKey&&!i.altKey&&!i.metaKey&&48<=i.keyCode&&1===i.key.length?s.key=i.key:i.key&&i.ctrlKey&&("_"===i.key&&(s.key=o.C0.US),"@"===i.key)&&(s.key=o.C0.NUL):65===i.keyCode&&(s.type=1);else{let e=a[i.keyCode],t=null==e?void 0:e[i.shiftKey?1:0];if(t)s.key=o.C0.ESC+t;else if(65<=i.keyCode&&i.keyCode<=90){let e=i.ctrlKey?i.keyCode-64:i.keyCode+32,t=String.fromCharCode(e);i.shiftKey&&(t=t.toUpperCase()),s.key=o.C0.ESC+t}else if("Dead"===i.key&&i.code.startsWith("Key")){let e=i.code.slice(3,4);i.shiftKey||(e=e.toLowerCase()),s.key=o.C0.ESC+e,s.cancel=!0}}else 65<=i.keyCode&&i.keyCode<=90?s.key=String.fromCharCode(i.keyCode-64):32===i.keyCode?s.key=o.C0.NUL:51<=i.keyCode&&i.keyCode<=55?s.key=String.fromCharCode(i.keyCode-51+27):56===i.keyCode?s.key=o.C0.DEL:219===i.keyCode?s.key=o.C0.ESC:220===i.keyCode?s.key=o.C0.FS:221===i.keyCode&&(s.key=o.C0.GS)}return s}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return 65535>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(i,e=0,r=i.length){let s="";for(let t=e;t>10))+String.fromCharCode(e%1024+56320)):s+=String.fromCharCode(e)}return s},t.StringToUtf32=class{constructor(){this._interim=0}clear(){this._interim=0}decode(i,r){let s=i.length;if(!s)return 0;let n=0,o=0;if(this._interim){let e=i.charCodeAt(o++);56320<=e&&e<=57343?r[n++]=1024*(this._interim-55296)+e-56320+65536:(r[n++]=this._interim,r[n++]=e),this._interim=0}for(let t=o;t=s)return this._interim=e,n;var a=i.charCodeAt(t);56320<=a&&a<=57343?r[n++]=1024*(e-55296)+a-56320+65536:(r[n++]=e,r[n++]=a)}else 65279!==e&&(r[n++]=e)}return n}},t.Utf8ToUtf32=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(o,a){var h=o.length;if(!h)return 0;let e,t,i,r,l=0,s=0,c=0;if(this.interim[0]){let e=!1,t=this.interim[0];t&=192==(224&t)?31:224==(240&t)?15:7;let i,r=0;for(;(i=63&this.interim[++r])&&r<4;)t=(t<<=6)|i;let s=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,n=s-r;for(;c=h)return 0;if(128!=(192&(i=o[c++]))){c--,e=!0;break}this.interim[r++]=i,t=(t<<=6)|63&i}e||(2==s?t<128?c--:a[l++]=t:3==s?t<2048||55296<=t&&t<=57343||65279===t||(a[l++]=t):t<65536||1114111=h)return this.interim[0]=e,l;128!=(192&(t=o[_++]))?_--:(s=(31&e)<<6|63&t)<128?_--:a[l++]=s}else if(224==(240&e)){if(_>=h)return this.interim[0]=e,l;if(128!=(192&(t=o[_++])))_--;else{if(_>=h)return this.interim[0]=e,this.interim[1]=t,l;128!=(192&(i=o[_++]))?_--:(s=(15&e)<<12|(63&t)<<6|63&i)<2048||55296<=s&&s<=57343||65279===s||(a[l++]=s)}}else if(240==(248&e)){if(_>=h)return this.interim[0]=e,l;if(128!=(192&(t=o[_++])))_--;else{if(_>=h)return this.interim[0]=e,this.interim[1]=t,l;if(128!=(192&(i=o[_++])))_--;else{if(_>=h)return this.interim[0]=e,this.interim[1]=t,this.interim[2]=i,l;128!=(192&(r=o[_++]))?_--:(s=(7&e)<<18|(63&t)<<12|(63&i)<<6|63&r)<65536||1114111{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;let r=i(8273),s=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],n=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]],o;t.UnicodeV6=class{constructor(){if(this.version="6",!o){o=new Uint8Array(65536),(0,r.fill)(o,1),(o[0]=0,r.fill)(o,0,1,32),(0,r.fill)(o,0,127,160),(0,r.fill)(o,2,4352,4448),o[9001]=2,o[9002]=2,(0,r.fill)(o,2,11904,42192),o[12351]=1,(0,r.fill)(o,2,44032,55204),(0,r.fill)(o,2,63744,64256),(0,r.fill)(o,2,65040,65050),(0,r.fill)(o,2,65072,65136),(0,r.fill)(o,2,65280,65377),(0,r.fill)(o,2,65504,65511);for(let e=0;e{let i,r=0,s=t.length-1;if(!(et[s][1]))for(;s>=r;)if(e>t[i=r+s>>1][1])r=1+i;else{if(!(e{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;let r=i(8460),n="undefined"==typeof queueMicrotask?e=>{Promise.resolve().then(e)}:queueMicrotask;t.WriteBuffer=class{constructor(e){this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0,this._onWriteParsed=new r.EventEmitter}get onWriteParsed(){return this._onWriteParsed.event}writeSync(e,t){if(void 0!==t&&this._syncCalls>t)this._syncCalls=0;else if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,!this._isSyncWriting){var i;for(this._isSyncWriting=!0;i=this._writeBuffer.shift();){this._action(i);let e=this._callbacks.shift();e&&e()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}}write(e,t){if(5e7this._innerWrite())),this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)}_innerWrite(e=0,i=!0){let r=e||Date.now();for(;this._writeBuffer.length>this._bufferOffset;){let e=this._writeBuffer[this._bufferOffset],t=this._action(e,i);if(t){let e=e=>12<=Date.now()-r?setTimeout(()=>this._innerWrite(0,e)):this._innerWrite(r,e);return void t.catch(e=>(n(()=>{throw e}),Promise.resolve(!1))).then(e)}var s=this._callbacks[this._bufferOffset];if(s&&s(),this._bufferOffset++,this._pendingData-=e.length,12<=Date.now()-r)break}this._writeBuffer.length>this._bufferOffset?(50this._innerWrite())):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0),this._onWriteParsed.fire()}}},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;let i=/^([\da-f])\/([\da-f])\/([\da-f])$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,n=/^[\da-f]+$/;function s(e,t){var i=e.toString(16),r=i.length<2?"0"+i:i;switch(t){case 4:return i[0];case 8:return r;case 12:return(r+r).slice(0,3);default:return r+r}}t.parseColor=function(e){if(e){let r=e.toLowerCase();if(0===r.indexOf("rgb:")){r=r.slice(4);let t=i.exec(r);if(t){let e=t[1]?15:t[4]?255:t[7]?4095:65535;return[Math.round(parseInt(t[1]||t[4]||t[7]||t[10],16)/e*255),Math.round(parseInt(t[2]||t[5]||t[8]||t[11],16)/e*255),Math.round(parseInt(t[3]||t[6]||t[9]||t[12],16)/e*255)]}}else if(0===r.indexOf("#")&&(r=r.slice(1),n.exec(r))&&[3,6,9,12].includes(r.length)){let t=r.length/3,i=[0,0,0];for(let e=0;e<3;++e){var s=parseInt(r.slice(t*e,t*e+t),16);i[e]=1==t?s<<4:2==t?s:3==t?s>>4:s>>8}return i}}},t.toRgbString=function(e,t=16){var[e,i,r]=e;return`rgb:${s(e,t)}/${s(i,t)}/`+s(r,t)}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;let s=i(482),r=i(8742),n=i(5770),o=[],a=(t.DcsParser=class{constructor(){this._handlers=Object.create(null),this._active=o,this._ident=0,this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=o}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);let i=this._handlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}reset(){if(this._active.length)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;0<=e;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=o,this._ident=0}hook(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||o,this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].hook(t);else this._handlerFb(this._ident,"HOOK",t)}put(t,i,r){if(this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].put(t,i,r);else this._handlerFb(this._ident,"PUT",(0,s.utf32ToString)(t,i,r))}unhook(r,s=!0){if(this._active.length){let e=!1,t=this._active.length-1,i=!1;if(this._stack.paused&&(t=this._stack.loopPosition-1,e=s,i=this._stack.fallThrough,this._stack.paused=!1),!i&&!1===e){for(;0<=t&&!0!==(e=this._active[t].unhook(r));t--)if(e instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=t,this._stack.fallThrough=!1,e;t--}for(;0<=t;t--)if((e=this._active[t].unhook(!1))instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=t,this._stack.fallThrough=!0,e}else this._handlerFb(this._ident,"UNHOOK",r);this._active=o,this._ident=0}},new r.Params);a.addParam(0),t.DcsHandler=class{constructor(e){this._handler=e,this._data="",this._params=a,this._hitLimit=!1}hook(e){this._params=1n.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}unhook(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data,this._params))instanceof Promise)return t.then(e=>(this._params=a,this._data="",this._hitLimit=!1,e));return this._params=a,this._data="",this._hitLimit=!1,t}}},2015:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;let r=i(844),s=i(8273),n=i(8742),o=i(6242),a=i(6351);class h{constructor(e){this.table=new Uint8Array(e)}setDefault(e,t){(0,s.fill)(this.table,e<<4|t)}add(e,t,i,r){this.table[t<<8|e]=i<<4|r}addMany(t,i,r,s){for(let e=0;e{let e=new h(4095),i=Array.apply(null,Array(256)).map((e,t)=>t),t=(e,t)=>i.slice(e,t),r=t(32,127),s=t(0,24);s.push(25),s.push.apply(s,t(28,32));var n=t(0,14);let o;for(o in e.setDefault(1,0),e.addMany(r,0,2,0),n)e.addMany([24,26,153,154],o,3,0),e.addMany(t(128,144),o,3,0),e.addMany(t(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(s,0,3,0),e.addMany(s,1,3,1),e.add(127,1,0,1),e.addMany(s,8,0,8),e.addMany(s,3,3,3),e.add(127,3,0,3),e.addMany(s,4,3,4),e.add(127,4,0,4),e.addMany(s,6,3,6),e.addMany(s,5,3,5),e.add(127,5,0,5),e.addMany(s,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(r,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(t(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(r,7,0,7),e.addMany(s,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(t(64,127),3,7,0),e.addMany(t(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(t(48,60),4,8,4),e.addMany(t(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(t(32,64),6,0,6),e.add(127,6,0,6),e.addMany(t(64,127),6,0,0),e.addMany(t(32,48),3,9,5),e.addMany(t(32,48),5,9,5),e.addMany(t(48,64),5,0,6),e.addMany(t(64,127),5,7,0),e.addMany(t(32,48),4,9,5),e.addMany(t(32,48),1,9,2),e.addMany(t(32,48),2,9,2),e.addMany(t(48,127),2,10,0),e.addMany(t(48,80),1,10,0),e.addMany(t(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(t(96,127),1,10,0),e.add(80,1,11,9),e.addMany(s,9,0,9),e.add(127,9,0,9),e.addMany(t(28,32),9,0,9),e.addMany(t(32,48),9,9,12),e.addMany(t(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(s,11,0,11),e.addMany(t(32,128),11,0,11),e.addMany(t(28,32),11,0,11),e.addMany(s,10,0,10),e.add(127,10,0,10),e.addMany(t(28,32),10,0,10),e.addMany(t(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(t(32,48),10,9,12),e.addMany(s,12,0,12),e.add(127,12,0,12),e.addMany(t(28,32),12,0,12),e.addMany(t(32,48),12,9,12),e.addMany(t(48,64),12,0,11),e.addMany(t(64,127),12,12,13),e.addMany(t(64,127),10,12,13),e.addMany(t(64,127),9,12,13),e.addMany(s,13,13,13),e.addMany(r,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(_,0,2,0),e.add(_,8,5,8),e.add(_,6,0,6),e.add(_,11,0,11),e.add(_,13,13,13),e})();class l extends r.Disposable{constructor(e=t.VT500_TRANSITION_TABLE){super(),this._transitions=e,this._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},this.initialState=0,this.currentState=this.initialState,this._params=new n.Params,this._params.addParam(0),this._collect=0,this.precedingCodepoint=0,this._printHandlerFb=(e,t,i)=>{},this._executeHandlerFb=e=>{},this._csiHandlerFb=(e,t)=>{},this._escHandlerFb=e=>{},this._errorHandlerFb=e=>e,this._printHandler=this._printHandlerFb,this._executeHandlers=Object.create(null),this._csiHandlers=Object.create(null),this._escHandlers=Object.create(null),this._oscParser=new o.OscParser,this._dcsParser=new a.DcsParser,this._errorHandler=this._errorHandlerFb,this.registerEscHandler({final:"\\"},()=>!0)}_identifier(i,e=[64,126]){let r=0;if(i.prefix){if(1t||t>e[1])throw new Error(`final must be in range ${e[0]} .. `+e[1]);return r=(r<<=8)|t}identToString(e){for(var t=[];e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")}dispose(){this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null),this._oscParser.dispose(),this._dcsParser.dispose()}setPrintHandler(e){this._printHandler=e}clearPrintHandler(){this._printHandler=this._printHandlerFb}registerEscHandler(e,t){e=this._identifier(e,[48,126]);void 0===this._escHandlers[e]&&(this._escHandlers[e]=[]);let i=this._escHandlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearEscHandler(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]}setEscHandlerFallback(e){this._escHandlerFb=e}setExecuteHandler(e,t){this._executeHandlers[e.charCodeAt(0)]=t}clearExecuteHandler(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]}setExecuteHandlerFallback(e){this._executeHandlerFb=e}registerCsiHandler(e,t){e=this._identifier(e);void 0===this._csiHandlers[e]&&(this._csiHandlers[e]=[]);let i=this._csiHandlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearCsiHandler(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]}setCsiHandlerFallback(e){this._csiHandlerFb=e}registerDcsHandler(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)}clearDcsHandler(e){this._dcsParser.clearHandler(this._identifier(e))}setDcsHandlerFallback(e){this._dcsParser.setHandlerFallback(e)}registerOscHandler(e,t){return this._oscParser.registerHandler(e,t)}clearOscHandler(e){this._oscParser.clearHandler(e)}setOscHandlerFallback(e){this._oscParser.setHandlerFallback(e)}setErrorHandler(e){this._errorHandler=e}clearErrorHandler(){this._errorHandler=this._errorHandlerFb}reset(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,(this.precedingCodepoint=0)!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])}_preserveStack(e,t,i,r,s){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=i,this._parseStack.transition=r,this._parseStack.chunkPos=s}parse(s,n,i){let o,a=0,h=0,l=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,l=this._parseStack.chunkPos+1;else{if(void 0===i||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");let e=this._parseStack.handlers,t=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===i&&-1>4){case 2:for(let e=r+1;;++e){if(e>=n||(a=s[e])<32||126=n||(a=s[e])<32||126=n||(a=s[e])<32||126=n||(a=s[e])<32||126=n||24===(a=s[e])||26===a||27===a||127=n||(a=s[e])<32||127{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;let r=i(5770),s=i(482),n=[];t.OscParser=class{constructor(){this._state=0,this._active=n,this._id=-1,this._handlers=Object.create(null),this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);let i=this._handlers[e];return i.push(t),{dispose:()=>{var e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=n}reset(){if(2===this._state)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;0<=e;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=n,this._id=-1,this._state=0}_start(){if(this._active=this._handlers[this._id]||n,this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].start();else this._handlerFb(this._id,"START")}_put(t,i,r){if(this._active.length)for(let e=this._active.length-1;0<=e;e--)this._active[e].put(t,i,r);else this._handlerFb(this._id,"PUT",(0,s.utf32ToString)(t,i,r))}start(){this.reset(),this._state=1}put(t,i,e){if(3!==this._state){if(1===this._state)for(;ir.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}end(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data))instanceof Promise)return t.then(e=>(this._data="",this._hitLimit=!1,e));return this._data="",this._hitLimit=!1,t}}},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;let s=2147483647;class n{constructor(e=32,t=32){if(this.maxLength=e,256<(this.maxSubParamsLength=t))throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}static fromArray(i){var r=new n;if(i.length)for(let e=Array.isArray(i[0])?1:0;e>8,r=255&this._subParamsIdx[e];0=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>s?s:e}}addSubParam(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>s?s:e,this._subParamsIdx[this.length-1]++}}hasSubParams(e){return 0<(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)}getSubParams(e){var t=this._subParamsIdx[e]>>8,e=255&this._subParamsIdx[e];return 0>8,r=255&this._subParamsIdx[e];0{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0,t.AddonManager=class{constructor(){this._addons=[]}dispose(){for(let e=this._addons.length-1;0<=e;e--)this._addons[e].instance.dispose()}loadAddon(e,t){let i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=()=>this._wrappedAddonDispose(i),t.activate(e)}_wrappedAddonDispose(i){if(!i.isDisposed){let t=-1;for(let e=0;e{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;let r=i(3785),s=i(511);t.BufferApiView=class{constructor(e,t){this._buffer=e,this.type=t}init(e){return this._buffer=e,this}get cursorY(){return this._buffer.y}get cursorX(){return this._buffer.x}get viewportY(){return this._buffer.ydisp}get baseY(){return this._buffer.ybase}get length(){return this._buffer.lines.length}getLine(e){e=this._buffer.lines.get(e);if(e)return new r.BufferLineApiView(e)}getNullCell(){return new s.CellData}}},3785:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;let r=i(511);t.BufferLineApiView=class{constructor(e){this._line=e}get isWrapped(){return this._line.isWrapped}get length(){return this._line.length}getCell(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new r.CellData)}translateToString(e,t,i){return this._line.translateToString(e,t,i)}}},8285:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;let r=i(8771),s=i(8460);t.BufferNamespaceApi=class{constructor(e){this._core=e,this._onBufferChange=new s.EventEmitter,this._normal=new r.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new r.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate(()=>this._onBufferChange.fire(this.active))}get onBufferChange(){return this._onBufferChange.event}get active(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")}get normal(){return this._normal.init(this._core.buffers.normal)}get alternate(){return this._alternate.init(this._core.buffers.alt)}}},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0,t.ParserApi=class{constructor(e){this._core=e}registerCsiHandler(e,t){return this._core.registerCsiHandler(e,e=>t(e.toArray()))}addCsiHandler(e,t){return this.registerCsiHandler(e,t)}registerDcsHandler(e,i){return this._core.registerDcsHandler(e,(e,t)=>i(e,t.toArray()))}addDcsHandler(e,t){return this.registerDcsHandler(e,t)}registerEscHandler(e,t){return this._core.registerEscHandler(e,t)}addEscHandler(e,t){return this.registerEscHandler(e,t)}registerOscHandler(e,t){return this._core.registerOscHandler(e,t)}addOscHandler(e,t){return this.registerOscHandler(e,t)}}},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0,t.UnicodeApi=class{constructor(e){this._core=e}register(e){this._core.unicodeService.register(e)}get versions(){return this._core.unicodeService.versions}get activeVersion(){return this._core.unicodeService.activeVersion}set activeVersion(e){this._core.unicodeService.activeVersion=e}}},744:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3=r.ybase&&(this.isUserScrolling=!1);var s=r.ydisp;r.ydisp=Math.max(Math.min(r.ydisp+e,r.ybase),0),s===r.ydisp||t||this._onScroll.fire(r.ydisp)}scrollPages(e){this.scrollLines(e*(this.rows-1))}scrollToTop(){this.scrollLines(-this.buffer.ydisp)}scrollToBottom(){this.scrollLines(this.buffer.ybase-this.buffer.ydisp)}scrollToLine(e){e-=this.buffer.ydisp;0!=e&&this.scrollLines(e)}},i=r([s(0,n.IOptionsService)],i);t.BufferService=i},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0,t.CharsetService=class{constructor(){this.glevel=0,this._charsets=[]}reset(){this.charset=void 0,this._charsets=[],this.glevel=0}setgLevel(e){this.glevel=e,this.charset=this._charsets[e]}setgCharset(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)}}},1753:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3!1},X10:{events:1,restrict:e=>4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,!(e.shift=!1))},VT200:{events:19,restrict:e=>32!==e.action},DRAG:{events:23,restrict:e=>32!==e.action||3!==e.button},ANY:{events:31,restrict:e=>!0}};function h(e,t){let i=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?i=(i|=64)|e.action:(i|=3&e.button,4&e.button&&(i|=64),8&e.button&&(i|=128),32===e.action?i|=32:0!==e.action||t||(i|=3)),i}let l=String.fromCharCode,c={DEFAULT:e=>{e=[h(e,!1)+32,e.col+32,e.row+32];return 255{var t=0===e.action&&4!==e.button?"m":"M";return`[<${h(e,!0)};${e.col};`+e.row+t},SGR_PIXELS:e=>{var t=0===e.action&&4!==e.button?"m":"M";return`[<${h(e,!0)};${e.x};`+e.y+t}};i=class{constructor(e,t){this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._onProtocolChange=new o.EventEmitter,this._lastEvent=null;for(let e of Object.keys(a))this.addProtocol(e,a[e]);for(let e of Object.keys(c))this.addEncoding(e,c[e]);this.reset()}addProtocol(e,t){this._protocols[e]=t}addEncoding(e,t){this._encodings[e]=t}get activeProtocol(){return this._activeProtocol}get areMouseEventsActive(){return 0!==this._protocols[this._activeProtocol].events}set activeProtocol(e){if(!this._protocols[e])throw new Error(`unknown protocol "${e}"`);this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)}get activeEncoding(){return this._activeEncoding}set activeEncoding(e){if(!this._encodings[e])throw new Error(`unknown encoding "${e}"`);this._activeEncoding=e}reset(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null}get onProtocolChange(){return this._onProtocolChange.event}triggerMouseEvent(e){var t;return!(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows||4===e.button&&32===e.action||3===e.button&&32!==e.action||4!==e.button&&(2===e.action||3===e.action)||(e.col++,e.row++,32===e.action&&this._lastEvent&&this._equalEvents(this._lastEvent,e,"SGR_PIXELS"===this._activeEncoding))||!this._protocols[this._activeProtocol].restrict(e)||((t=this._encodings[this._activeEncoding](e))&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,0))}explainEvents(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}}_equalEvents(e,t,i){if(i){if(e.x!==t.x)return!1;if(e.y!==t.y)return!1}else{if(e.col!==t.col)return!1;if(e.row!==t.row)return!1}return e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift}},i=r([s(0,n.IBufferService),s(1,n.ICoreService)],i);t.CoreMouseService=i},6975:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._scrollToBottom=void 0}),this.modes=(0,a.clone)(l),this.decPrivateModes=(0,a.clone)(c)}get onData(){return this._onData.event}get onUserInput(){return this._onUserInput.event}get onBinary(){return this._onBinary.event}reset(){this.modes=(0,a.clone)(l),this.decPrivateModes=(0,a.clone)(c)}triggerDataEvent(e,t=!1){var i;this._optionsService.rawOptions.disableStdin||((i=this._bufferService.buffer).ybase!==i.ydisp&&this._scrollToBottom(),t&&this._onUserInput.fire(),this._logService.debug(`sending data "${e}"`,()=>e.split("").map(e=>e.charCodeAt(0))),this._onData.fire(e))}triggerBinaryEvent(e){this._optionsService.rawOptions.disableStdin||(this._logService.debug(`sending binary "${e}"`,()=>e.split("").map(e=>e.charCodeAt(0))),this._onBinary.fire(e))}},i=r([s(1,n.IBufferService),s(2,n.ILogService),s(3,n.IOptionsService)],i);t.CoreService=i},9074:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DecorationService=void 0;let r=i(8055),s=i(8460),n=i(844),o=i(6106),a={xmin:0,xmax:0};class h extends n.Disposable{constructor(){super(...arguments),this._decorations=new o.SortedList(e=>null==e?void 0:e.marker.line),this._onDecorationRegistered=this.register(new s.EventEmitter),this._onDecorationRemoved=this.register(new s.EventEmitter)}get onDecorationRegistered(){return this._onDecorationRegistered.event}get onDecorationRemoved(){return this._onDecorationRemoved.event}get decorations(){return this._decorations.values()}registerDecoration(e){if(!e.marker.isDisposed){let t=new l(e);if(t){let e=t.marker.onDispose(()=>t.dispose());t.onDispose(()=>{t&&(this._decorations.delete(t)&&this._onDecorationRemoved.fire(t),e.dispose())}),this._decorations.insert(t),this._onDecorationRegistered.fire(t)}return t}}reset(){for(var e of this._decorations.values())e.dispose();this._decorations.clear()}*getDecorationsAtCell(e,t,i){var r,s,n;for(n of this._decorations.getKeyIterator(t))r=null!=(r=n.options.x)?r:0,s=r+(null!=(s=n.options.width)?s:1),r<=e&&e{var t;a.xmin=null!=(t=e.options.x)?t:0,a.xmax=a.xmin+(null!=(t=e.options.width)?t:1),i>=a.xmin&&ithis._end&&(this._end=e)}markRangeDirty(e,t){var i;tthis._end&&(this._end=t)}markAllDirty(){this.markRangeDirty(0,this._bufferService.rows-1)}},n=r([s(0,i.IBufferService)],n);t.DirtyRowService=n},4348:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;let r=i(2585),n=i(8343);class s{constructor(...e){this._entries=new Map;for(var[t,i]of e)this.set(t,i)}set(e,t){var i=this._entries.get(e);return this._entries.set(e,t),i}forEach(i){this._entries.forEach((e,t)=>i(t,e))}has(e){return this._entries.has(e)}get(e){return this._entries.get(e)}}t.ServiceCollection=s,t.InstantiationService=class{constructor(){this._services=new s,this._services.set(r.IInstantiationService,this)}setService(e,t){this._services.set(e,t)}getService(e){return this._services.get(e)}createInstance(i,...e){let r=(0,n.getServiceDependencies)(i).sort((e,t)=>e.index-t.index),s=[];for(let t of r){let e=this._services.get(t.id);if(!e)throw new Error(`[createInstance] ${i.name} depends on UNKNOWN service ${t.id}.`);s.push(e)}var t=0{"logLevel"===e&&this._updateLogLevel()})}_updateLogLevel(){this.logLevel=o[this._optionsService.rawOptions.logLevel]}_evalLazyOptionalParams(t){for(let e=0;e{Object.defineProperty(s,"__esModule",{value:!0}),s.OptionsService=s.DEFAULT_OPTIONS=void 0;let n=t(8460),i=t(6114),r=(s.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,customGlyphs:!0,drawBoldTextInBrightColors:!0,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",lineHeight:1,letterSpacing:0,linkHandler:null,logLevel:"info",scrollback:1e3,scrollSensitivity:1,screenReaderMode:!1,smoothScrollDuration:0,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!1,allowTransparency:!1,tabStopWidth:8,theme:{},rightClickSelectsWord:i.isMac,windowOptions:{},windowsMode:!1,wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1,overviewRulerWidth:0},["normal","bold","100","200","300","400","500","600","700","800","900"]);s.OptionsService=class{constructor(i){this._onOptionChange=new n.EventEmitter;var r=Object.assign({},s.DEFAULT_OPTIONS);for(let t in i)if(t in r)try{let e=i[t];r[t]=this._sanitizeAndValidateOption(t,e)}catch(i){console.error(i)}this.rawOptions=r,this.options=Object.assign({},r),this._setupOptions()}get onOptionChange(){return this._onOptionChange.event}_setupOptions(){var t=e=>{if(e in s.DEFAULT_OPTIONS)return this.rawOptions[e];throw new Error(`No option with key "${e}"`)},i=(e,t)=>{if(!(e in s.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);t=this._sanitizeAndValidateOption(e,t),this.rawOptions[e]!==t&&(this.rawOptions[e]=t,this._onOptionChange.fire(e))};for(let e in this.rawOptions){var r={get:t.bind(this,e),set:i.bind(this,e)};Object.defineProperty(this.options,e,r)}}_sanitizeAndValidateOption(e,t){switch(e){case"cursorStyle":if("block"!==(t=t||s.DEFAULT_OPTIONS[e])&&"underline"!==t&&"bar"!==t)throw new Error(`"${t}" is not a valid value for `+e);break;case"wordSeparator":t=t||s.DEFAULT_OPTIONS[e];break;case"fontWeight":case"fontWeightBold":"number"==typeof t&&1<=t&&t<=1e3||(t=r.includes(t)?t:s.DEFAULT_OPTIONS[e]);break;case"cursorWidth":t=Math.floor(t);case"lineHeight":case"tabStopWidth":if(t<1)throw new Error(e+" cannot be less than 1, value: "+t);break;case"minimumContrastRatio":t=Math.max(1,Math.min(21,Math.round(10*t)/10));break;case"scrollback":if((t=Math.min(t,4294967295))<0)throw new Error(e+" cannot be less than 0, value: "+t);break;case"fastScrollSensitivity":case"scrollSensitivity":if(t<=0)throw new Error(e+" cannot be less than or equal to 0, value: "+t);case"rows":case"cols":if(!t&&0!==t)throw new Error(e+" must be numeric, value: "+t)}return t}}},2660:function(e,t,i){var r=this&&this.__decorate||function(e,t,i,r){var s,n=arguments.length,o=n<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;0<=a;a--)(s=e[a])&&(o=(n<3?s(o):3this._removeMarkerFromLink(t,e)),this._dataByLinkId.set(t.id,t),t.id}let e=i,t=this._getEntryIdKey(e),s=this._entriesWithId.get(t);if(s)return this.addLineToLink(s.id,r.ybase+r.y),s.id;let n=r.addMarker(r.ybase+r.y),o={id:this._nextId++,key:this._getEntryIdKey(e),data:e,lines:[n]};return n.onDispose(()=>this._removeMarkerFromLink(o,n)),this._entriesWithId.set(o.key,o),this._dataByLinkId.set(o.id,o),o.id}addLineToLink(e,t){let i=this._dataByLinkId.get(e);if(i&&i.lines.every(e=>e.line!==t)){let e=this._bufferService.buffer.addMarker(t);i.lines.push(e),e.onDispose(()=>this._removeMarkerFromLink(i,e))}}getLinkData(e){return null==(e=this._dataByLinkId.get(e))?void 0:e.data}_getEntryIdKey(e){return e.id+";;"+e.uri}_removeMarkerFromLink(e,t){t=e.lines.indexOf(t);-1!==t&&(e.lines.splice(t,1),0===e.lines.length)&&(void 0!==e.data.id&&this._entriesWithId.delete(e.key),this._dataByLinkId.delete(e.id))}},n=r([s(0,i.IBufferService)],n);t.OscLinkService=n},8343:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0,t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e.di$dependencies||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);function s(e,t,i){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");var r;r=s,i=i,(e=e).di$target===e?e.di$dependencies.push({id:r,index:i}):(e.di$dependencies=[{id:r,index:i}],e.di$target=e)}return s.toString=()=>e,t.serviceRegistry.set(e,s),s}},2585:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IDecorationService=t.IUnicodeService=t.IOscLinkService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.IDirtyRowService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;var r,i=i(8343);t.IBufferService=(0,i.createDecorator)("BufferService"),t.ICoreMouseService=(0,i.createDecorator)("CoreMouseService"),t.ICoreService=(0,i.createDecorator)("CoreService"),t.ICharsetService=(0,i.createDecorator)("CharsetService"),t.IDirtyRowService=(0,i.createDecorator)("DirtyRowService"),t.IInstantiationService=(0,i.createDecorator)("InstantiationService"),(r=t.LogLevelEnum||(t.LogLevelEnum={}))[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r[r.OFF=4]="OFF",t.ILogService=(0,i.createDecorator)("LogService"),t.IOptionsService=(0,i.createDecorator)("OptionsService"),t.IOscLinkService=(0,i.createDecorator)("OscLinkService"),t.IUnicodeService=(0,i.createDecorator)("UnicodeService"),t.IDecorationService=(0,i.createDecorator)("DecorationService")},1480:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;let r=i(8460),s=i(225);t.UnicodeService=class{constructor(){this._providers=Object.create(null),this._active="",this._onChange=new r.EventEmitter;var e=new s.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}get onChange(){return this._onChange.event}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(i){let r=0;var s=i.length;for(let t=0;t=s)return r+this.wcwidth(e);var n=i.charCodeAt(t);56320<=n&&n<=57343?e=1024*(e-55296)+n-56320+65536:r+=this.wcwidth(n)}r+=this.wcwidth(e)}return r}}}},r={};function a(e){var t=r[e];return void 0!==t||(t=r[e]={exports:{}},i[e].call(t.exports,t,t.exports,a)),t.exports}var h={};{var l=h;Object.defineProperty(l,"__esModule",{value:!0}),l.Terminal=void 0;let t=a(3236),e=a(9042),i=a(7975),r=a(7090),s=a(5741),n=a(8285),o=["cols","rows"];l.Terminal=class{constructor(e){this._core=new t.Terminal(e),this._addonManager=new s.AddonManager,this._publicOptions=Object.assign({},this._core.options);var i=e=>this._core.options[e],r=(e,t)=>{this._checkReadonlyOptions(e),this._core.options[e]=t};for(let t in this._core.options){let e={get:i.bind(this,t),set:r.bind(this,t)};Object.defineProperty(this._publicOptions,t,e)}}_checkReadonlyOptions(e){if(o.includes(e))throw new Error(`Option "${e}" can only be set in the constructor`)}_checkProposedApi(){if(!this._core.optionsService.rawOptions.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")}get onBell(){return this._core.onBell}get onBinary(){return this._core.onBinary}get onCursorMove(){return this._core.onCursorMove}get onData(){return this._core.onData}get onKey(){return this._core.onKey}get onLineFeed(){return this._core.onLineFeed}get onRender(){return this._core.onRender}get onResize(){return this._core.onResize}get onScroll(){return this._core.onScroll}get onSelectionChange(){return this._core.onSelectionChange}get onTitleChange(){return this._core.onTitleChange}get onWriteParsed(){return this._core.onWriteParsed}get element(){return this._core.element}get parser(){return this._checkProposedApi(),this._parser||(this._parser=new i.ParserApi(this._core)),this._parser}get unicode(){return this._checkProposedApi(),new r.UnicodeApi(this._core)}get textarea(){return this._core.textarea}get rows(){return this._core.rows}get cols(){return this._core.cols}get buffer(){return this._checkProposedApi(),this._buffer||(this._buffer=new n.BufferNamespaceApi(this._core)),this._buffer}get markers(){return this._checkProposedApi(),this._core.markers}get modes(){var e=this._core.coreService.decPrivateModes;let t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}}get options(){return this._publicOptions}set options(e){for(var t in e)this._publicOptions[t]=e[t]}blur(){this._core.blur()}focus(){this._core.focus()}resize(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)}open(e){this._core.open(e)}attachCustomKeyEventHandler(e){this._core.attachCustomKeyEventHandler(e)}registerLinkProvider(e){return this._checkProposedApi(),this._core.registerLinkProvider(e)}registerCharacterJoiner(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)}deregisterCharacterJoiner(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)}registerMarker(e=0){return this._verifyIntegers(e),this._core.addMarker(e)}registerDecoration(e){var t;return this._checkProposedApi(),this._verifyPositiveIntegers(null!=(t=e.x)?t:0,null!=(t=e.width)?t:0,null!=(t=e.height)?t:0),this._core.registerDecoration(e)}hasSelection(){return this._core.hasSelection()}select(e,t,i){this._verifyIntegers(e,t,i),this._core.select(e,t,i)}getSelection(){return this._core.getSelection()}getSelectionPosition(){return this._core.getSelectionPosition()}clearSelection(){this._core.clearSelection()}selectAll(){this._core.selectAll()}selectLines(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)}dispose(){this._addonManager.dispose(),this._core.dispose()}scrollLines(e){this._verifyIntegers(e),this._core.scrollLines(e)}scrollPages(e){this._verifyIntegers(e),this._core.scrollPages(e)}scrollToTop(){this._core.scrollToTop()}scrollToBottom(){this._core.scrollToBottom()}scrollToLine(e){this._verifyIntegers(e),this._core.scrollToLine(e)}clear(){this._core.clear()}write(e,t){this._core.write(e,t)}writeln(e,t){this._core.write(e),this._core.write("\r\n",t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){return this._addonManager.loadAddon(this,e)}static get strings(){return e}_verifyIntegers(...e){for(var t of e)if(t===1/0||isNaN(t)||t%1!=0)throw new Error("This API only accepts integers")}_verifyPositiveIntegers(...e){for(var t of e)if(t&&(t===1/0||isNaN(t)||t%1!=0||t<0))throw new Error("This API only accepts positive integers")}}}return h}) \ No newline at end of file diff --git a/public/scripts/zlib-adler32-min.js b/public/scripts/zlib-adler32-min.js index 242a0f1e..96197fa8 100644 --- a/public/scripts/zlib-adler32-min.js +++ b/public/scripts/zlib-adler32-min.js @@ -1 +1 @@ -"undefined"==typeof ZLIB&&alert("ZLIB is not defined. SRC zlib.js before zlib-adler32.js"),function(){var b=65521,v=5552;ZLIB.adler32=function(r,e,o,t){if("string"==typeof e){var a,d=r,c=e,C=o,h=t,A=d>>>16&65535;if(d&=65535,1==h)d+=255&c.charCodeAt(C),b<=d&&(d-=b),b<=(A+=d)&&(A-=b);else{if(null===c)return 1;if(h<16){for(;h--;)A+=d+=255&c.charCodeAt(C++);return b<=d&&(d-=b),d|(A%=b)<<16}for(;v<=h;){for(h-=v,a=347;A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A+=d+=255&c.charCodeAt(C++))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)),--a;);d%=b,A%=b}if(h){for(;16<=h;)h-=16,A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A+=d+=255&c.charCodeAt(C++))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++));for(;h--;)A+=d+=255&c.charCodeAt(C++);d%=b,A%=b}}return d|A<<16}var f,n=r,i=e,u=o,l=t,s=n>>>16&65535;if(n&=65535,1==l)n+=i[u],b<=n&&(n-=b),b<=(s+=n)&&(s-=b);else{if(null===i)return 1;if(l<16){for(;l--;)s+=n+=i[u++];return b<=n&&(n-=b),n|(s%=b)<<16}for(;v<=l;){for(l-=v,f=347;s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s+=n+=i[u++])+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]),--f;);n%=b,s%=b}if(l){for(;16<=l;)l-=16,s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s+=n+=i[u++])+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]))+(n+=i[u++]);for(;l--;)s+=n+=i[u++];n%=b,s%=b}}return n|s<<16},ZLIB.adler32_combine=function(r,e,o){var t,a;return o<0?4294967295:(a=(o%=b)*(t=65535&r),b<=(t+=(65535&e)+b-1)&&(t-=b),b<=t&&(t-=b),b<<1<=(a=a%b+((r>>16&65535)+(e>>16&65535)+b-o))&&(a-=b<<1),b<=a&&(a-=b),t|a<<16)}}() \ No newline at end of file +"undefined"==typeof ZLIB&&alert("ZLIB is not defined. SRC zlib.js before zlib-adler32.js"),(()=>{var b=65521,v=5552;ZLIB.adler32=function(r,e,o,t){if("string"==typeof e){var a,d=r,c=e,C=o,h=t,A=d>>>16&65535;if(d&=65535,1==h)d+=255&c.charCodeAt(C),b<=d&&(d-=b),b<=(A+=d)&&(A-=b);else{if(null===c)return 1;if(h<16){for(;h--;)A+=d+=255&c.charCodeAt(C++);return b<=d&&(d-=b),d|(A%=b)<<16}for(;v<=h;){for(h-=v,a=347;A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A+=d+=255&c.charCodeAt(C++))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)),--a;);d%=b,A%=b}if(h){for(;16<=h;)h-=16,A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A=(A+=d+=255&c.charCodeAt(C++))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++)))+(d+=255&c.charCodeAt(C++));for(;h--;)A+=d+=255&c.charCodeAt(C++);d%=b,A%=b}}return d|A<<16}var f,n=r,i=e,l=o,u=t,s=n>>>16&65535;if(n&=65535,1==u)n+=i[l],b<=n&&(n-=b),b<=(s+=n)&&(s-=b);else{if(null===i)return 1;if(u<16){for(;u--;)s+=n+=i[l++];return b<=n&&(n-=b),n|(s%=b)<<16}for(;v<=u;){for(u-=v,f=347;s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s+=n+=i[l++])+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]),--f;);n%=b,s%=b}if(u){for(;16<=u;)u-=16,s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s+=n+=i[l++])+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]))+(n+=i[l++]);for(;u--;)s+=n+=i[l++];n%=b,s%=b}}return n|s<<16},ZLIB.adler32_combine=function(r,e,o){var t,a;return o<0?4294967295:(a=(o%=b)*(t=65535&r),b<=(t+=(65535&e)+b-1)&&(t-=b),b<=t&&(t-=b),b<<1<=(a=a%b+((r>>16&65535)+(e>>16&65535)+b-o))&&(a-=b<<1),b<=a&&(a-=b),t|a<<16)}})() \ No newline at end of file diff --git a/public/scripts/zlib-crc32-min.js b/public/scripts/zlib-crc32-min.js index 9423f21d..d788cde4 100644 --- a/public/scripts/zlib-crc32-min.js +++ b/public/scripts/zlib-crc32-min.js @@ -1 +1 @@ -"undefined"==typeof ZLIB&&alert("ZLIB is not defined. SRC zlib.js before zlib-crc32.js"),function(){var C=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117];ZLIB.crc32=function(r,e,o,n){if("string"==typeof e){var t=r,f=e,c=o,a=n;if(null==f)return 0;for(t^=4294967295;8<=a;)t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,a-=8;if(a)for(;t=C[255&(t^f.charCodeAt(c++))]^t>>>8,--a;);return 4294967295^t}var i=r,u=e,d=o,A=n;if(null==u)return 0;for(i^=4294967295;8<=A;)i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,i=C[255&(i^u[d++])]^i>>>8,A-=8;if(A)for(;i=C[255&(i^u[d++])]^i>>>8,--A;);return 4294967295^i};function a(r,e){for(var o=0,n=0;e;)1&e&&(n^=r[o]),e>>=1,o++;return n}function i(r,e){for(var o=0;o<32;o++)r[o]=a(e,e[o])}ZLIB.crc32_combine=function(r,e,o){var n,t,f,c;if(!(o<=0)){for(f=new Array(32),(c=new Array(32))[0]=3988292384,n=t=1;n<32;n++)c[n]=t,t<<=1;for(i(f,c),i(c,f);i(f,c),1&o&&(r=a(f,r)),0!=(o>>=1)&&(i(c,f),1&o&&(r=a(c,r)),0!=(o>>=1)););r^=e}return r}}() \ No newline at end of file +"undefined"==typeof ZLIB&&alert("ZLIB is not defined. SRC zlib.js before zlib-crc32.js"),(()=>{var C=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117];function a(r,e){for(var o=0,n=0;e;)1&e&&(n^=r[o]),e>>=1,o++;return n}function i(r,e){for(var o=0;o<32;o++)r[o]=a(e,e[o])}ZLIB.crc32=function(r,e,o,n){if("string"==typeof e){var t=r,f=e,c=o,a=n;if(null==f)return 0;for(t^=4294967295;8<=a;)t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,t=C[255&(t^f.charCodeAt(c++))]^t>>>8,a-=8;if(a)for(;t=C[255&(t^f.charCodeAt(c++))]^t>>>8,--a;);return 4294967295^t}var i=r,d=e,u=o,A=n;if(null==d)return 0;for(i^=4294967295;8<=A;)i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,i=C[255&(i^d[u++])]^i>>>8,A-=8;if(A)for(;i=C[255&(i^d[u++])]^i>>>8,--A;);return 4294967295^i},ZLIB.crc32_combine=function(r,e,o){var n,t,f,c;if(!(o<=0)){for(f=new Array(32),(c=new Array(32))[0]=3988292384,n=t=1;n<32;n++)c[n]=t,t<<=1;for(i(f,c),i(c,f);i(f,c),1&o&&(r=a(f,r)),0!=(o>>=1)&&(i(c,f),1&o&&(r=a(c,r)),0!=(o>>=1)););r^=e}return r}})() \ No newline at end of file diff --git a/public/scripts/zlib-inflate-min.js b/public/scripts/zlib-inflate-min.js index 8c047621..0ff3fb2e 100644 --- a/public/scripts/zlib-inflate-min.js +++ b/public/scripts/zlib-inflate-min.js @@ -1 +1 @@ -"undefined"==typeof ZLIB&&alert("ZLIB is not defined. SRC zlib.js before zlib-inflate.js"),function(){var Y=11,q=29,C=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],O=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,203,69],T=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],y=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];function G(t,a){for(var i,s,o,l,e,b,v,p,n,d,r,h,c,f,u,m,_,k,g,w,x=t.next,Z=2==a?t.distbits:t.lenbits,I=t.work,L=t.lens,B=2==a?t.nlen:0,R=t.codes,E=1==a?t.nlen:2==a?t.ndist:19,A=new Array(16),S=new Array(16),z=0;z<=15;z++)A[z]=0;for(i=0;iw?(f.op=k[g+I[i]],f.val=m[_+I[i]]):f.op=96,d=1<>>b)+(r-=d)]=f,0!=r;);for(d=1<>>=1;if(n=0!=d?(n&d-1)+d:0,i++,0==--A[z]){if(z==o)break;z=L[B+I[i]]}if(l>>4),a<48&&(a&=15)),1==i&&"function"==typeof ZLIB.adler32?t.checksum_function=ZLIB.adler32:2==i&&"function"==typeof ZLIB.crc32?t.checksum_function=ZLIB.crc32:t.checksum_function=o,a&&(a<8||15>>8&255],0,2)}function W(t,a){a.strm=t,a.left=t.avail_out,a.next=t.next_in,a.have=t.avail_in,a.hold=t.state.hold,a.bits=t.state.bits}function X(t){var a=t.strm;a.next_in=t.next,a.avail_out=t.left,a.avail_in=t.have,a.state.hold=t.hold,a.state.bits=t.bits}function $(t){t.hold=0,t.bits=0}function tt(t){return 0!=t.have&&(t.have--,t.hold+=(255&t.strm.input_data.charCodeAt(t.next++))<>>=a,t.bits-=a}function ot(t){t.hold>>>=7&t.bits,t.bits-=7&t.bits}function lt(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}var et=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];ZLIB.inflate=function(t,a){var i,s,o,l,e,b,v,p,n,d,r,h,c=-1,f=-1;if(!t||!t.state||!t.input_data&&0!=t.avail_in)return ZLIB.Z_STREAM_ERROR;(i=t.state).mode==Y&&(i.mode=12),W(t,s={}),o=s.have,l=s.left,n=ZLIB.Z_OK;t:for(;;)switch(i.mode){case 0:if(0==i.wrap)i.mode=12;else{if(!at(s,16))break t;if(2&i.wrap&&35615==s.hold)i.check=t.checksum_function(0,null,0,0),V(t,s.hold),$(s),i.mode=1;else if(i.flags=0,null!==i.head&&(i.head.done=-1),!(1&i.wrap)||((it(s,8)<<8)+(s.hold>>>8))%31)t.msg="incorrect header check",i.mode=q;else if(it(s,4)!=ZLIB.Z_DEFLATED)t.msg="unknown compression method",i.mode=q;else{if(st(s,4),p=it(s,4)+8,0==i.wbits)i.wbits=p;else if(p>i.wbits){t.msg="invalid window size",i.mode=q;break}i.dmax=1<>>8&1),512&i.flags&&V(t,s.hold),$(s),i.mode=2;case 2:if(!at(s,32))break t;null!==i.head&&(i.head.time=s.hold),512&i.flags&&(x=s.hold,t.state.check=t.checksum_function(t.state.check,[255&x,x>>>8&255,x>>>16&255,x>>>24&255],0,4)),$(s),i.mode=3;case 3:if(!at(s,16))break t;null!==i.head&&(i.head.xflags=255&s.hold,i.head.os=s.hold>>>8),512&i.flags&&V(t,s.hold),$(s),i.mode=4;case 4:if(1024&i.flags){if(!at(s,16))break t;i.length=s.hold,null!==i.head&&(i.head.extra_len=s.hold),512&i.flags&&V(t,s.hold),$(s),i.head.extra=""}else null!==i.head&&(i.head.extra=null);i.mode=5;case 5:if(1024&i.flags&&((e=(e=i.length)>s.have?s.have:e)&&(null!==i.head&&null!==i.head.extra&&(p=i.head.extra_len-i.length,i.head.extra+=t.input_data.substring(s.next,s.next+(p+e>i.head.extra_max?i.head.extra_max-p:e))),512&i.flags&&(i.check=t.checksum_function(i.check,t.input_data,s.next,e)),s.have-=e,s.next+=e,i.length-=e),i.length))break t;i.length=0,i.mode=6;case 6:if(2048&i.flags){if(0==s.have)break t;for(null!==i.head&&null===i.head.name&&(i.head.name=""),e=0;p=t.input_data.charAt(s.next+e),e++,"\0"!==p&&(null!==i.head&&i.length>>9&1,i.head.done=1),t.adler=i.check=t.checksum_function(0,null,0,0),i.mode=Y;break;case 9:if(!at(s,32))break t;t.adler=i.check=lt(s.hold),$(s),i.mode=10;case 10:if(0==i.havedict)return X(s),ZLIB.Z_NEED_DICT;t.adler=i.check=t.checksum_function(0,null,0,0),i.mode=Y;case Y:if(a==ZLIB.Z_BLOCK||a==ZLIB.Z_TREES)break t;case 12:if(i.last)ot(s),i.mode=26;else{if(!at(s,3))break t;switch(i.last=it(s,1),st(s,1),it(s,2)){case 0:i.mode=13;break;case 1:u=m=void 0;var u,m=i;for(J=J||[{op:96,bits:7,val:0},{op:0,bits:8,val:80},{op:0,bits:8,val:16},{op:20,bits:8,val:115},{op:18,bits:7,val:31},{op:0,bits:8,val:112},{op:0,bits:8,val:48},{op:0,bits:9,val:192},{op:16,bits:7,val:10},{op:0,bits:8,val:96},{op:0,bits:8,val:32},{op:0,bits:9,val:160},{op:0,bits:8,val:0},{op:0,bits:8,val:128},{op:0,bits:8,val:64},{op:0,bits:9,val:224},{op:16,bits:7,val:6},{op:0,bits:8,val:88},{op:0,bits:8,val:24},{op:0,bits:9,val:144},{op:19,bits:7,val:59},{op:0,bits:8,val:120},{op:0,bits:8,val:56},{op:0,bits:9,val:208},{op:17,bits:7,val:17},{op:0,bits:8,val:104},{op:0,bits:8,val:40},{op:0,bits:9,val:176},{op:0,bits:8,val:8},{op:0,bits:8,val:136},{op:0,bits:8,val:72},{op:0,bits:9,val:240},{op:16,bits:7,val:4},{op:0,bits:8,val:84},{op:0,bits:8,val:20},{op:21,bits:8,val:227},{op:19,bits:7,val:43},{op:0,bits:8,val:116},{op:0,bits:8,val:52},{op:0,bits:9,val:200},{op:17,bits:7,val:13},{op:0,bits:8,val:100},{op:0,bits:8,val:36},{op:0,bits:9,val:168},{op:0,bits:8,val:4},{op:0,bits:8,val:132},{op:0,bits:8,val:68},{op:0,bits:9,val:232},{op:16,bits:7,val:8},{op:0,bits:8,val:92},{op:0,bits:8,val:28},{op:0,bits:9,val:152},{op:20,bits:7,val:83},{op:0,bits:8,val:124},{op:0,bits:8,val:60},{op:0,bits:9,val:216},{op:18,bits:7,val:23},{op:0,bits:8,val:108},{op:0,bits:8,val:44},{op:0,bits:9,val:184},{op:0,bits:8,val:12},{op:0,bits:8,val:140},{op:0,bits:8,val:76},{op:0,bits:9,val:248},{op:16,bits:7,val:3},{op:0,bits:8,val:82},{op:0,bits:8,val:18},{op:21,bits:8,val:163},{op:19,bits:7,val:35},{op:0,bits:8,val:114},{op:0,bits:8,val:50},{op:0,bits:9,val:196},{op:17,bits:7,val:11},{op:0,bits:8,val:98},{op:0,bits:8,val:34},{op:0,bits:9,val:164},{op:0,bits:8,val:2},{op:0,bits:8,val:130},{op:0,bits:8,val:66},{op:0,bits:9,val:228},{op:16,bits:7,val:7},{op:0,bits:8,val:90},{op:0,bits:8,val:26},{op:0,bits:9,val:148},{op:20,bits:7,val:67},{op:0,bits:8,val:122},{op:0,bits:8,val:58},{op:0,bits:9,val:212},{op:18,bits:7,val:19},{op:0,bits:8,val:106},{op:0,bits:8,val:42},{op:0,bits:9,val:180},{op:0,bits:8,val:10},{op:0,bits:8,val:138},{op:0,bits:8,val:74},{op:0,bits:9,val:244},{op:16,bits:7,val:5},{op:0,bits:8,val:86},{op:0,bits:8,val:22},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:118},{op:0,bits:8,val:54},{op:0,bits:9,val:204},{op:17,bits:7,val:15},{op:0,bits:8,val:102},{op:0,bits:8,val:38},{op:0,bits:9,val:172},{op:0,bits:8,val:6},{op:0,bits:8,val:134},{op:0,bits:8,val:70},{op:0,bits:9,val:236},{op:16,bits:7,val:9},{op:0,bits:8,val:94},{op:0,bits:8,val:30},{op:0,bits:9,val:156},{op:20,bits:7,val:99},{op:0,bits:8,val:126},{op:0,bits:8,val:62},{op:0,bits:9,val:220},{op:18,bits:7,val:27},{op:0,bits:8,val:110},{op:0,bits:8,val:46},{op:0,bits:9,val:188},{op:0,bits:8,val:14},{op:0,bits:8,val:142},{op:0,bits:8,val:78},{op:0,bits:9,val:252},{op:96,bits:7,val:0},{op:0,bits:8,val:81},{op:0,bits:8,val:17},{op:21,bits:8,val:131},{op:18,bits:7,val:31},{op:0,bits:8,val:113},{op:0,bits:8,val:49},{op:0,bits:9,val:194},{op:16,bits:7,val:10},{op:0,bits:8,val:97},{op:0,bits:8,val:33},{op:0,bits:9,val:162},{op:0,bits:8,val:1},{op:0,bits:8,val:129},{op:0,bits:8,val:65},{op:0,bits:9,val:226},{op:16,bits:7,val:6},{op:0,bits:8,val:89},{op:0,bits:8,val:25},{op:0,bits:9,val:146},{op:19,bits:7,val:59},{op:0,bits:8,val:121},{op:0,bits:8,val:57},{op:0,bits:9,val:210},{op:17,bits:7,val:17},{op:0,bits:8,val:105},{op:0,bits:8,val:41},{op:0,bits:9,val:178},{op:0,bits:8,val:9},{op:0,bits:8,val:137},{op:0,bits:8,val:73},{op:0,bits:9,val:242},{op:16,bits:7,val:4},{op:0,bits:8,val:85},{op:0,bits:8,val:21},{op:16,bits:8,val:258},{op:19,bits:7,val:43},{op:0,bits:8,val:117},{op:0,bits:8,val:53},{op:0,bits:9,val:202},{op:17,bits:7,val:13},{op:0,bits:8,val:101},{op:0,bits:8,val:37},{op:0,bits:9,val:170},{op:0,bits:8,val:5},{op:0,bits:8,val:133},{op:0,bits:8,val:69},{op:0,bits:9,val:234},{op:16,bits:7,val:8},{op:0,bits:8,val:93},{op:0,bits:8,val:29},{op:0,bits:9,val:154},{op:20,bits:7,val:83},{op:0,bits:8,val:125},{op:0,bits:8,val:61},{op:0,bits:9,val:218},{op:18,bits:7,val:23},{op:0,bits:8,val:109},{op:0,bits:8,val:45},{op:0,bits:9,val:186},{op:0,bits:8,val:13},{op:0,bits:8,val:141},{op:0,bits:8,val:77},{op:0,bits:9,val:250},{op:16,bits:7,val:3},{op:0,bits:8,val:83},{op:0,bits:8,val:19},{op:21,bits:8,val:195},{op:19,bits:7,val:35},{op:0,bits:8,val:115},{op:0,bits:8,val:51},{op:0,bits:9,val:198},{op:17,bits:7,val:11},{op:0,bits:8,val:99},{op:0,bits:8,val:35},{op:0,bits:9,val:166},{op:0,bits:8,val:3},{op:0,bits:8,val:131},{op:0,bits:8,val:67},{op:0,bits:9,val:230},{op:16,bits:7,val:7},{op:0,bits:8,val:91},{op:0,bits:8,val:27},{op:0,bits:9,val:150},{op:20,bits:7,val:67},{op:0,bits:8,val:123},{op:0,bits:8,val:59},{op:0,bits:9,val:214},{op:18,bits:7,val:19},{op:0,bits:8,val:107},{op:0,bits:8,val:43},{op:0,bits:9,val:182},{op:0,bits:8,val:11},{op:0,bits:8,val:139},{op:0,bits:8,val:75},{op:0,bits:9,val:246},{op:16,bits:7,val:5},{op:0,bits:8,val:87},{op:0,bits:8,val:23},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:119},{op:0,bits:8,val:55},{op:0,bits:9,val:206},{op:17,bits:7,val:15},{op:0,bits:8,val:103},{op:0,bits:8,val:39},{op:0,bits:9,val:174},{op:0,bits:8,val:7},{op:0,bits:8,val:135},{op:0,bits:8,val:71},{op:0,bits:9,val:238},{op:16,bits:7,val:9},{op:0,bits:8,val:95},{op:0,bits:8,val:31},{op:0,bits:9,val:158},{op:20,bits:7,val:99},{op:0,bits:8,val:127},{op:0,bits:8,val:63},{op:0,bits:9,val:222},{op:18,bits:7,val:27},{op:0,bits:8,val:111},{op:0,bits:8,val:47},{op:0,bits:9,val:190},{op:0,bits:8,val:15},{op:0,bits:8,val:143},{op:0,bits:8,val:79},{op:0,bits:9,val:254},{op:96,bits:7,val:0},{op:0,bits:8,val:80},{op:0,bits:8,val:16},{op:20,bits:8,val:115},{op:18,bits:7,val:31},{op:0,bits:8,val:112},{op:0,bits:8,val:48},{op:0,bits:9,val:193},{op:16,bits:7,val:10},{op:0,bits:8,val:96},{op:0,bits:8,val:32},{op:0,bits:9,val:161},{op:0,bits:8,val:0},{op:0,bits:8,val:128},{op:0,bits:8,val:64},{op:0,bits:9,val:225},{op:16,bits:7,val:6},{op:0,bits:8,val:88},{op:0,bits:8,val:24},{op:0,bits:9,val:145},{op:19,bits:7,val:59},{op:0,bits:8,val:120},{op:0,bits:8,val:56},{op:0,bits:9,val:209},{op:17,bits:7,val:17},{op:0,bits:8,val:104},{op:0,bits:8,val:40},{op:0,bits:9,val:177},{op:0,bits:8,val:8},{op:0,bits:8,val:136},{op:0,bits:8,val:72},{op:0,bits:9,val:241},{op:16,bits:7,val:4},{op:0,bits:8,val:84},{op:0,bits:8,val:20},{op:21,bits:8,val:227},{op:19,bits:7,val:43},{op:0,bits:8,val:116},{op:0,bits:8,val:52},{op:0,bits:9,val:201},{op:17,bits:7,val:13},{op:0,bits:8,val:100},{op:0,bits:8,val:36},{op:0,bits:9,val:169},{op:0,bits:8,val:4},{op:0,bits:8,val:132},{op:0,bits:8,val:68},{op:0,bits:9,val:233},{op:16,bits:7,val:8},{op:0,bits:8,val:92},{op:0,bits:8,val:28},{op:0,bits:9,val:153},{op:20,bits:7,val:83},{op:0,bits:8,val:124},{op:0,bits:8,val:60},{op:0,bits:9,val:217},{op:18,bits:7,val:23},{op:0,bits:8,val:108},{op:0,bits:8,val:44},{op:0,bits:9,val:185},{op:0,bits:8,val:12},{op:0,bits:8,val:140},{op:0,bits:8,val:76},{op:0,bits:9,val:249},{op:16,bits:7,val:3},{op:0,bits:8,val:82},{op:0,bits:8,val:18},{op:21,bits:8,val:163},{op:19,bits:7,val:35},{op:0,bits:8,val:114},{op:0,bits:8,val:50},{op:0,bits:9,val:197},{op:17,bits:7,val:11},{op:0,bits:8,val:98},{op:0,bits:8,val:34},{op:0,bits:9,val:165},{op:0,bits:8,val:2},{op:0,bits:8,val:130},{op:0,bits:8,val:66},{op:0,bits:9,val:229},{op:16,bits:7,val:7},{op:0,bits:8,val:90},{op:0,bits:8,val:26},{op:0,bits:9,val:149},{op:20,bits:7,val:67},{op:0,bits:8,val:122},{op:0,bits:8,val:58},{op:0,bits:9,val:213},{op:18,bits:7,val:19},{op:0,bits:8,val:106},{op:0,bits:8,val:42},{op:0,bits:9,val:181},{op:0,bits:8,val:10},{op:0,bits:8,val:138},{op:0,bits:8,val:74},{op:0,bits:9,val:245},{op:16,bits:7,val:5},{op:0,bits:8,val:86},{op:0,bits:8,val:22},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:118},{op:0,bits:8,val:54},{op:0,bits:9,val:205},{op:17,bits:7,val:15},{op:0,bits:8,val:102},{op:0,bits:8,val:38},{op:0,bits:9,val:173},{op:0,bits:8,val:6},{op:0,bits:8,val:134},{op:0,bits:8,val:70},{op:0,bits:9,val:237},{op:16,bits:7,val:9},{op:0,bits:8,val:94},{op:0,bits:8,val:30},{op:0,bits:9,val:157},{op:20,bits:7,val:99},{op:0,bits:8,val:126},{op:0,bits:8,val:62},{op:0,bits:9,val:221},{op:18,bits:7,val:27},{op:0,bits:8,val:110},{op:0,bits:8,val:46},{op:0,bits:9,val:189},{op:0,bits:8,val:14},{op:0,bits:8,val:142},{op:0,bits:8,val:78},{op:0,bits:9,val:253},{op:96,bits:7,val:0},{op:0,bits:8,val:81},{op:0,bits:8,val:17},{op:21,bits:8,val:131},{op:18,bits:7,val:31},{op:0,bits:8,val:113},{op:0,bits:8,val:49},{op:0,bits:9,val:195},{op:16,bits:7,val:10},{op:0,bits:8,val:97},{op:0,bits:8,val:33},{op:0,bits:9,val:163},{op:0,bits:8,val:1},{op:0,bits:8,val:129},{op:0,bits:8,val:65},{op:0,bits:9,val:227},{op:16,bits:7,val:6},{op:0,bits:8,val:89},{op:0,bits:8,val:25},{op:0,bits:9,val:147},{op:19,bits:7,val:59},{op:0,bits:8,val:121},{op:0,bits:8,val:57},{op:0,bits:9,val:211},{op:17,bits:7,val:17},{op:0,bits:8,val:105},{op:0,bits:8,val:41},{op:0,bits:9,val:179},{op:0,bits:8,val:9},{op:0,bits:8,val:137},{op:0,bits:8,val:73},{op:0,bits:9,val:243},{op:16,bits:7,val:4},{op:0,bits:8,val:85},{op:0,bits:8,val:21},{op:16,bits:8,val:258},{op:19,bits:7,val:43},{op:0,bits:8,val:117},{op:0,bits:8,val:53},{op:0,bits:9,val:203},{op:17,bits:7,val:13},{op:0,bits:8,val:101},{op:0,bits:8,val:37},{op:0,bits:9,val:171},{op:0,bits:8,val:5},{op:0,bits:8,val:133},{op:0,bits:8,val:69},{op:0,bits:9,val:235},{op:16,bits:7,val:8},{op:0,bits:8,val:93},{op:0,bits:8,val:29},{op:0,bits:9,val:155},{op:20,bits:7,val:83},{op:0,bits:8,val:125},{op:0,bits:8,val:61},{op:0,bits:9,val:219},{op:18,bits:7,val:23},{op:0,bits:8,val:109},{op:0,bits:8,val:45},{op:0,bits:9,val:187},{op:0,bits:8,val:13},{op:0,bits:8,val:141},{op:0,bits:8,val:77},{op:0,bits:9,val:251},{op:16,bits:7,val:3},{op:0,bits:8,val:83},{op:0,bits:8,val:19},{op:21,bits:8,val:195},{op:19,bits:7,val:35},{op:0,bits:8,val:115},{op:0,bits:8,val:51},{op:0,bits:9,val:199},{op:17,bits:7,val:11},{op:0,bits:8,val:99},{op:0,bits:8,val:35},{op:0,bits:9,val:167},{op:0,bits:8,val:3},{op:0,bits:8,val:131},{op:0,bits:8,val:67},{op:0,bits:9,val:231},{op:16,bits:7,val:7},{op:0,bits:8,val:91},{op:0,bits:8,val:27},{op:0,bits:9,val:151},{op:20,bits:7,val:67},{op:0,bits:8,val:123},{op:0,bits:8,val:59},{op:0,bits:9,val:215},{op:18,bits:7,val:19},{op:0,bits:8,val:107},{op:0,bits:8,val:43},{op:0,bits:9,val:183},{op:0,bits:8,val:11},{op:0,bits:8,val:139},{op:0,bits:8,val:75},{op:0,bits:9,val:247},{op:16,bits:7,val:5},{op:0,bits:8,val:87},{op:0,bits:8,val:23},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:119},{op:0,bits:8,val:55},{op:0,bits:9,val:207},{op:17,bits:7,val:15},{op:0,bits:8,val:103},{op:0,bits:8,val:39},{op:0,bits:9,val:175},{op:0,bits:8,val:7},{op:0,bits:8,val:135},{op:0,bits:8,val:71},{op:0,bits:9,val:239},{op:16,bits:7,val:9},{op:0,bits:8,val:95},{op:0,bits:8,val:31},{op:0,bits:9,val:159},{op:20,bits:7,val:99},{op:0,bits:8,val:127},{op:0,bits:8,val:63},{op:0,bits:9,val:223},{op:18,bits:7,val:27},{op:0,bits:8,val:111},{op:0,bits:8,val:47},{op:0,bits:9,val:191},{op:0,bits:8,val:15},{op:0,bits:8,val:143},{op:0,bits:8,val:79},{op:0,bits:9,val:255}],Q=Q||[{op:16,bits:5,val:1},{op:23,bits:5,val:257},{op:19,bits:5,val:17},{op:27,bits:5,val:4097},{op:17,bits:5,val:5},{op:25,bits:5,val:1025},{op:21,bits:5,val:65},{op:29,bits:5,val:16385},{op:16,bits:5,val:3},{op:24,bits:5,val:513},{op:20,bits:5,val:33},{op:28,bits:5,val:8193},{op:18,bits:5,val:9},{op:26,bits:5,val:2049},{op:22,bits:5,val:129},{op:64,bits:5,val:0},{op:16,bits:5,val:2},{op:23,bits:5,val:385},{op:19,bits:5,val:25},{op:27,bits:5,val:6145},{op:17,bits:5,val:7},{op:25,bits:5,val:1537},{op:21,bits:5,val:97},{op:29,bits:5,val:24577},{op:16,bits:5,val:4},{op:24,bits:5,val:769},{op:20,bits:5,val:49},{op:28,bits:5,val:12289},{op:18,bits:5,val:13},{op:26,bits:5,val:3073},{op:22,bits:5,val:193},{op:64,bits:5,val:0}],m.lencode=0,m.distcode=512,u=0;u<512;u++)m.codes[u]=J[u];for(u=0;u<32;u++)m.codes[u+512]=Q[u];if(m.lenbits=9,m.distbits=5,i.mode=19,a!=ZLIB.Z_TREES)break;st(s,2);break t;case 2:i.mode=16;break;case 3:t.msg="invalid block type",i.mode=q}st(s,2)}break;case 13:if(ot(s),!at(s,32))break t;if((65535&s.hold)!=(s.hold>>>16&65535^65535)){t.msg="invalid stored block lengths",i.mode=q;break}if(i.length=65535&s.hold,$(s),i.mode=14,a==ZLIB.Z_TREES)break t;case 14:i.mode=15;case 15:if(e=i.length){if(0==(e=(e=e>s.have?s.have:e)>s.left?s.left:e))break t;t.output_data+=t.input_data.substring(s.next,s.next+e),t.next_out+=e,s.have-=e,s.next+=e,s.left-=e,i.length-=e}else i.mode=Y;break;case 16:if(!at(s,14))break t;if(i.nlen=it(s,5)+257,st(s,5),i.ndist=it(s,5)+1,st(s,5),i.ncode=it(s,4)+4,st(s,4),286i.nlen+i.ndist){t.msg="invalid bit length repeat",i.mode=q;break}for(;e--;)i.lens[i.have++]=p}}if(i.mode==q)break;if(0==i.lens[256]){t.msg="invalid code -- missing end-of-block",i.mode=q;break}if(i.next=0,i.lencode=i.next,i.lenbits=9,n=G(i,1)){t.msg="invalid literal/lengths set",i.mode=q;break}if(i.distcode=i.next,i.distbits=6,n=G(i,2)){t.msg="invalid distances set",i.mode=q;break}if(i.mode=19,a==ZLIB.Z_TREES)break t;case 19:i.mode=20;case 20:if(6<=s.have&&258<=s.left){X(s),I=Z=y=g=k=_=P=U=j=H=T=O=C=z=N=F=D=S=K=A=E=R=B=L=x=w=void 0;var _,k,g,w=t,x=l,Z=-1,I=-1,L=w.state,B=w.input_data,R=w.next_in,E=R+w.avail_in-5,A=w.next_out,K=A-(x-w.avail_out),S=A+(w.avail_out-257),D=L.wsize,F=L.whave,N=L.wnext,z=L.window,C=L.hold,O=L.bits,T=L.codes,H=L.lencode,j=L.distcode,U=(1<>>=k=_.bits,O-=k,0==(k=_.op))w.output_data+=String.fromCharCode(_.val),A++;else{if(!(16&k)){if(0==(64&k)){_=T[H+(_.val+(C&(1<>>=k,O-=k),O<15&&(C+=(255&B.charCodeAt(R++))<>>=k=_.bits,O-=k,!(16&(k=_.op))){if(0==(64&k)){_=T[j+(_.val+(C&(1<>>=k,O-=k,(k=A-K)>>3)<<3))-1,w.next_in=R-=g,w.next_out=A,w.avail_in=R>>v.bits)],!(v.bits+b.bits<=s.bits);)if(!tt(s))break t;st(s,v.bits),i.back+=v.bits}if(st(s,b.bits),i.back+=b.bits,i.length=b.val,0==b.op){i.mode=25;break}if(32&b.op){i.back=-1,i.mode=Y;break}if(64&b.op){t.msg="invalid literal/length code",i.mode=q;break}i.extra=15&b.op,i.mode=21;case 21:if(i.extra){if(!at(s,i.extra))break t;i.length+=it(s,i.extra),st(s,i.extra),i.back+=i.extra}i.was=i.length,i.mode=22;case 22:for(;!((b=i.codes[i.distcode+it(s,i.distbits)]).bits<=s.bits);)if(!tt(s))break t;if(0==(240&b.op)){for(v=b;b=i.codes[i.distcode+v.val+(it(s,v.bits+v.op)>>>v.bits)],!(v.bits+b.bits<=s.bits);)if(!tt(s))break t;st(s,v.bits),i.back+=v.bits}if(st(s,b.bits),i.back+=b.bits,64&b.op){t.msg="invalid distance code",i.mode=q;break}i.offset=b.val,i.extra=15&b.op,i.mode=23;case 23:if(i.extra){if(!at(s,i.extra))break t;i.offset+=it(s,i.extra),st(s,i.extra),i.back+=i.extra}i.mode=24;case 24:if(0==s.left)break t;if(e=l-s.left,i.offset>e){if((e=i.offset-e)>i.whave&&i.sane){t.msg="invalid distance too far back",i.mode=q;break}f=(c=e>i.wnext?(e-=i.wnext,i.wsize-e):i.wnext-e,-1),e>i.length&&(e=i.length)}else c=-1,f=t.next_out-i.offset,e=i.length;if(e>s.left&&(e=s.left),s.left-=e,i.length-=e,0<=c)t.output_data+=i.window.substring(c,c+e),t.next_out+=e,e=0;else for(t.next_out+=e;t.output_data+=t.output_data.charAt(f++),--e;);0==i.length&&(i.mode=20);break;case 25:if(0==s.left)break t;t.output_data+=String.fromCharCode(i.length),t.next_out++,s.left--,i.mode=20;break;case 26:if(i.wrap){if(!at(s,32))break t;if(l-=s.left,t.total_out+=l,i.total+=l,l&&(t.adler=i.check=t.checksum_function(i.check,t.output_data,t.output_data.length-l,l)),l=s.left,(i.flags?s.hold:lt(s.hold))!=i.check){t.msg="incorrect data check",i.mode=q;break}$(s)}i.mode=27;case 27:if(i.wrap&&i.flags){if(!at(s,32))break t;if(s.hold!=(4294967295&i.total)){t.msg="incorrect length check",i.mode=q;break}$(s)}i.mode=28;case 28:n=ZLIB.Z_STREAM_END;break t;case q:n=ZLIB.Z_DATA_ERROR;break t;case 30:return ZLIB.Z_MEM_ERROR;default:return ZLIB.Z_STREAM_ERROR}return X(s),(i.wsize||l!=t.avail_out&&i.mode=r.wsize?r.window=d.output_data.substring(h-r.wsize):r.whave+h{var Y=11,q=29,C=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],O=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,203,69],T=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],y=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];function G(t,a){for(var i,s,o,l,e,b,v,p,n,d,r,h,c,f,u,m,_,k,g,w,x=t.next,Z=2==a?t.distbits:t.lenbits,I=t.work,L=t.lens,B=2==a?t.nlen:0,R=t.codes,E=1==a?t.nlen:2==a?t.ndist:19,A=new Array(16),S=new Array(16),z=0;z<=15;z++)A[z]=0;for(i=0;iw?(f.op=k[g+I[i]],f.val=m[_+I[i]]):f.op=96,d=1<>>b)+(r-=d)]=f,0!=r;);for(d=1<>>=1;if(n=0!=d?(n&d-1)+d:0,i++,0==--A[z]){if(z==o)break;z=L[B+I[i]]}if(l>>4),a<48&&(a&=15)),1==i&&"function"==typeof ZLIB.adler32?t.checksum_function=ZLIB.adler32:2==i&&"function"==typeof ZLIB.crc32?t.checksum_function=ZLIB.crc32:t.checksum_function=o,a&&(a<8||15>>8&255],0,2)}function W(t,a){a.strm=t,a.left=t.avail_out,a.next=t.next_in,a.have=t.avail_in,a.hold=t.state.hold,a.bits=t.state.bits}function X(t){var a=t.strm;a.next_in=t.next,a.avail_out=t.left,a.avail_in=t.have,a.state.hold=t.hold,a.state.bits=t.bits}function $(t){t.hold=0,t.bits=0}function tt(t){return 0!=t.have&&(t.have--,t.hold+=(255&t.strm.input_data.charCodeAt(t.next++))<>>=a,t.bits-=a}function ot(t){t.hold>>>=7&t.bits,t.bits-=7&t.bits}function lt(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}var et=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];ZLIB.inflate=function(t,a){var i,s,o,l,e,b,v,p,n,d,r,h,c=-1,f=-1;if(!t||!t.state||!t.input_data&&0!=t.avail_in)return ZLIB.Z_STREAM_ERROR;(i=t.state).mode==Y&&(i.mode=12),W(t,s={}),o=s.have,l=s.left,n=ZLIB.Z_OK;t:for(;;)switch(i.mode){case 0:if(0==i.wrap)i.mode=12;else{if(!at(s,16))break t;if(2&i.wrap&&35615==s.hold)i.check=t.checksum_function(0,null,0,0),V(t,s.hold),$(s),i.mode=1;else if(i.flags=0,null!==i.head&&(i.head.done=-1),!(1&i.wrap)||((it(s,8)<<8)+(s.hold>>>8))%31)t.msg="incorrect header check",i.mode=q;else if(it(s,4)!=ZLIB.Z_DEFLATED)t.msg="unknown compression method",i.mode=q;else{if(st(s,4),p=it(s,4)+8,0==i.wbits)i.wbits=p;else if(p>i.wbits){t.msg="invalid window size",i.mode=q;break}i.dmax=1<>>8&1),512&i.flags&&V(t,s.hold),$(s),i.mode=2;case 2:if(!at(s,32))break t;null!==i.head&&(i.head.time=s.hold),512&i.flags&&(x=s.hold,t.state.check=t.checksum_function(t.state.check,[255&x,x>>>8&255,x>>>16&255,x>>>24&255],0,4)),$(s),i.mode=3;case 3:if(!at(s,16))break t;null!==i.head&&(i.head.xflags=255&s.hold,i.head.os=s.hold>>>8),512&i.flags&&V(t,s.hold),$(s),i.mode=4;case 4:if(1024&i.flags){if(!at(s,16))break t;i.length=s.hold,null!==i.head&&(i.head.extra_len=s.hold),512&i.flags&&V(t,s.hold),$(s),i.head.extra=""}else null!==i.head&&(i.head.extra=null);i.mode=5;case 5:if(1024&i.flags&&((e=(e=i.length)>s.have?s.have:e)&&(null!==i.head&&null!==i.head.extra&&(p=i.head.extra_len-i.length,i.head.extra+=t.input_data.substring(s.next,s.next+(p+e>i.head.extra_max?i.head.extra_max-p:e))),512&i.flags&&(i.check=t.checksum_function(i.check,t.input_data,s.next,e)),s.have-=e,s.next+=e,i.length-=e),i.length))break t;i.length=0,i.mode=6;case 6:if(2048&i.flags){if(0==s.have)break t;for(null!==i.head&&null===i.head.name&&(i.head.name=""),e=0;p=t.input_data.charAt(s.next+e),e++,"\0"!==p&&(null!==i.head&&i.length>>9&1,i.head.done=1),t.adler=i.check=t.checksum_function(0,null,0,0),i.mode=Y;break;case 9:if(!at(s,32))break t;t.adler=i.check=lt(s.hold),$(s),i.mode=10;case 10:if(0==i.havedict)return X(s),ZLIB.Z_NEED_DICT;t.adler=i.check=t.checksum_function(0,null,0,0),i.mode=Y;case Y:if(a==ZLIB.Z_BLOCK||a==ZLIB.Z_TREES)break t;case 12:if(i.last)ot(s),i.mode=26;else{if(!at(s,3))break t;switch(i.last=it(s,1),st(s,1),it(s,2)){case 0:i.mode=13;break;case 1:u=m=void 0;var u,m=i;for(J=J||[{op:96,bits:7,val:0},{op:0,bits:8,val:80},{op:0,bits:8,val:16},{op:20,bits:8,val:115},{op:18,bits:7,val:31},{op:0,bits:8,val:112},{op:0,bits:8,val:48},{op:0,bits:9,val:192},{op:16,bits:7,val:10},{op:0,bits:8,val:96},{op:0,bits:8,val:32},{op:0,bits:9,val:160},{op:0,bits:8,val:0},{op:0,bits:8,val:128},{op:0,bits:8,val:64},{op:0,bits:9,val:224},{op:16,bits:7,val:6},{op:0,bits:8,val:88},{op:0,bits:8,val:24},{op:0,bits:9,val:144},{op:19,bits:7,val:59},{op:0,bits:8,val:120},{op:0,bits:8,val:56},{op:0,bits:9,val:208},{op:17,bits:7,val:17},{op:0,bits:8,val:104},{op:0,bits:8,val:40},{op:0,bits:9,val:176},{op:0,bits:8,val:8},{op:0,bits:8,val:136},{op:0,bits:8,val:72},{op:0,bits:9,val:240},{op:16,bits:7,val:4},{op:0,bits:8,val:84},{op:0,bits:8,val:20},{op:21,bits:8,val:227},{op:19,bits:7,val:43},{op:0,bits:8,val:116},{op:0,bits:8,val:52},{op:0,bits:9,val:200},{op:17,bits:7,val:13},{op:0,bits:8,val:100},{op:0,bits:8,val:36},{op:0,bits:9,val:168},{op:0,bits:8,val:4},{op:0,bits:8,val:132},{op:0,bits:8,val:68},{op:0,bits:9,val:232},{op:16,bits:7,val:8},{op:0,bits:8,val:92},{op:0,bits:8,val:28},{op:0,bits:9,val:152},{op:20,bits:7,val:83},{op:0,bits:8,val:124},{op:0,bits:8,val:60},{op:0,bits:9,val:216},{op:18,bits:7,val:23},{op:0,bits:8,val:108},{op:0,bits:8,val:44},{op:0,bits:9,val:184},{op:0,bits:8,val:12},{op:0,bits:8,val:140},{op:0,bits:8,val:76},{op:0,bits:9,val:248},{op:16,bits:7,val:3},{op:0,bits:8,val:82},{op:0,bits:8,val:18},{op:21,bits:8,val:163},{op:19,bits:7,val:35},{op:0,bits:8,val:114},{op:0,bits:8,val:50},{op:0,bits:9,val:196},{op:17,bits:7,val:11},{op:0,bits:8,val:98},{op:0,bits:8,val:34},{op:0,bits:9,val:164},{op:0,bits:8,val:2},{op:0,bits:8,val:130},{op:0,bits:8,val:66},{op:0,bits:9,val:228},{op:16,bits:7,val:7},{op:0,bits:8,val:90},{op:0,bits:8,val:26},{op:0,bits:9,val:148},{op:20,bits:7,val:67},{op:0,bits:8,val:122},{op:0,bits:8,val:58},{op:0,bits:9,val:212},{op:18,bits:7,val:19},{op:0,bits:8,val:106},{op:0,bits:8,val:42},{op:0,bits:9,val:180},{op:0,bits:8,val:10},{op:0,bits:8,val:138},{op:0,bits:8,val:74},{op:0,bits:9,val:244},{op:16,bits:7,val:5},{op:0,bits:8,val:86},{op:0,bits:8,val:22},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:118},{op:0,bits:8,val:54},{op:0,bits:9,val:204},{op:17,bits:7,val:15},{op:0,bits:8,val:102},{op:0,bits:8,val:38},{op:0,bits:9,val:172},{op:0,bits:8,val:6},{op:0,bits:8,val:134},{op:0,bits:8,val:70},{op:0,bits:9,val:236},{op:16,bits:7,val:9},{op:0,bits:8,val:94},{op:0,bits:8,val:30},{op:0,bits:9,val:156},{op:20,bits:7,val:99},{op:0,bits:8,val:126},{op:0,bits:8,val:62},{op:0,bits:9,val:220},{op:18,bits:7,val:27},{op:0,bits:8,val:110},{op:0,bits:8,val:46},{op:0,bits:9,val:188},{op:0,bits:8,val:14},{op:0,bits:8,val:142},{op:0,bits:8,val:78},{op:0,bits:9,val:252},{op:96,bits:7,val:0},{op:0,bits:8,val:81},{op:0,bits:8,val:17},{op:21,bits:8,val:131},{op:18,bits:7,val:31},{op:0,bits:8,val:113},{op:0,bits:8,val:49},{op:0,bits:9,val:194},{op:16,bits:7,val:10},{op:0,bits:8,val:97},{op:0,bits:8,val:33},{op:0,bits:9,val:162},{op:0,bits:8,val:1},{op:0,bits:8,val:129},{op:0,bits:8,val:65},{op:0,bits:9,val:226},{op:16,bits:7,val:6},{op:0,bits:8,val:89},{op:0,bits:8,val:25},{op:0,bits:9,val:146},{op:19,bits:7,val:59},{op:0,bits:8,val:121},{op:0,bits:8,val:57},{op:0,bits:9,val:210},{op:17,bits:7,val:17},{op:0,bits:8,val:105},{op:0,bits:8,val:41},{op:0,bits:9,val:178},{op:0,bits:8,val:9},{op:0,bits:8,val:137},{op:0,bits:8,val:73},{op:0,bits:9,val:242},{op:16,bits:7,val:4},{op:0,bits:8,val:85},{op:0,bits:8,val:21},{op:16,bits:8,val:258},{op:19,bits:7,val:43},{op:0,bits:8,val:117},{op:0,bits:8,val:53},{op:0,bits:9,val:202},{op:17,bits:7,val:13},{op:0,bits:8,val:101},{op:0,bits:8,val:37},{op:0,bits:9,val:170},{op:0,bits:8,val:5},{op:0,bits:8,val:133},{op:0,bits:8,val:69},{op:0,bits:9,val:234},{op:16,bits:7,val:8},{op:0,bits:8,val:93},{op:0,bits:8,val:29},{op:0,bits:9,val:154},{op:20,bits:7,val:83},{op:0,bits:8,val:125},{op:0,bits:8,val:61},{op:0,bits:9,val:218},{op:18,bits:7,val:23},{op:0,bits:8,val:109},{op:0,bits:8,val:45},{op:0,bits:9,val:186},{op:0,bits:8,val:13},{op:0,bits:8,val:141},{op:0,bits:8,val:77},{op:0,bits:9,val:250},{op:16,bits:7,val:3},{op:0,bits:8,val:83},{op:0,bits:8,val:19},{op:21,bits:8,val:195},{op:19,bits:7,val:35},{op:0,bits:8,val:115},{op:0,bits:8,val:51},{op:0,bits:9,val:198},{op:17,bits:7,val:11},{op:0,bits:8,val:99},{op:0,bits:8,val:35},{op:0,bits:9,val:166},{op:0,bits:8,val:3},{op:0,bits:8,val:131},{op:0,bits:8,val:67},{op:0,bits:9,val:230},{op:16,bits:7,val:7},{op:0,bits:8,val:91},{op:0,bits:8,val:27},{op:0,bits:9,val:150},{op:20,bits:7,val:67},{op:0,bits:8,val:123},{op:0,bits:8,val:59},{op:0,bits:9,val:214},{op:18,bits:7,val:19},{op:0,bits:8,val:107},{op:0,bits:8,val:43},{op:0,bits:9,val:182},{op:0,bits:8,val:11},{op:0,bits:8,val:139},{op:0,bits:8,val:75},{op:0,bits:9,val:246},{op:16,bits:7,val:5},{op:0,bits:8,val:87},{op:0,bits:8,val:23},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:119},{op:0,bits:8,val:55},{op:0,bits:9,val:206},{op:17,bits:7,val:15},{op:0,bits:8,val:103},{op:0,bits:8,val:39},{op:0,bits:9,val:174},{op:0,bits:8,val:7},{op:0,bits:8,val:135},{op:0,bits:8,val:71},{op:0,bits:9,val:238},{op:16,bits:7,val:9},{op:0,bits:8,val:95},{op:0,bits:8,val:31},{op:0,bits:9,val:158},{op:20,bits:7,val:99},{op:0,bits:8,val:127},{op:0,bits:8,val:63},{op:0,bits:9,val:222},{op:18,bits:7,val:27},{op:0,bits:8,val:111},{op:0,bits:8,val:47},{op:0,bits:9,val:190},{op:0,bits:8,val:15},{op:0,bits:8,val:143},{op:0,bits:8,val:79},{op:0,bits:9,val:254},{op:96,bits:7,val:0},{op:0,bits:8,val:80},{op:0,bits:8,val:16},{op:20,bits:8,val:115},{op:18,bits:7,val:31},{op:0,bits:8,val:112},{op:0,bits:8,val:48},{op:0,bits:9,val:193},{op:16,bits:7,val:10},{op:0,bits:8,val:96},{op:0,bits:8,val:32},{op:0,bits:9,val:161},{op:0,bits:8,val:0},{op:0,bits:8,val:128},{op:0,bits:8,val:64},{op:0,bits:9,val:225},{op:16,bits:7,val:6},{op:0,bits:8,val:88},{op:0,bits:8,val:24},{op:0,bits:9,val:145},{op:19,bits:7,val:59},{op:0,bits:8,val:120},{op:0,bits:8,val:56},{op:0,bits:9,val:209},{op:17,bits:7,val:17},{op:0,bits:8,val:104},{op:0,bits:8,val:40},{op:0,bits:9,val:177},{op:0,bits:8,val:8},{op:0,bits:8,val:136},{op:0,bits:8,val:72},{op:0,bits:9,val:241},{op:16,bits:7,val:4},{op:0,bits:8,val:84},{op:0,bits:8,val:20},{op:21,bits:8,val:227},{op:19,bits:7,val:43},{op:0,bits:8,val:116},{op:0,bits:8,val:52},{op:0,bits:9,val:201},{op:17,bits:7,val:13},{op:0,bits:8,val:100},{op:0,bits:8,val:36},{op:0,bits:9,val:169},{op:0,bits:8,val:4},{op:0,bits:8,val:132},{op:0,bits:8,val:68},{op:0,bits:9,val:233},{op:16,bits:7,val:8},{op:0,bits:8,val:92},{op:0,bits:8,val:28},{op:0,bits:9,val:153},{op:20,bits:7,val:83},{op:0,bits:8,val:124},{op:0,bits:8,val:60},{op:0,bits:9,val:217},{op:18,bits:7,val:23},{op:0,bits:8,val:108},{op:0,bits:8,val:44},{op:0,bits:9,val:185},{op:0,bits:8,val:12},{op:0,bits:8,val:140},{op:0,bits:8,val:76},{op:0,bits:9,val:249},{op:16,bits:7,val:3},{op:0,bits:8,val:82},{op:0,bits:8,val:18},{op:21,bits:8,val:163},{op:19,bits:7,val:35},{op:0,bits:8,val:114},{op:0,bits:8,val:50},{op:0,bits:9,val:197},{op:17,bits:7,val:11},{op:0,bits:8,val:98},{op:0,bits:8,val:34},{op:0,bits:9,val:165},{op:0,bits:8,val:2},{op:0,bits:8,val:130},{op:0,bits:8,val:66},{op:0,bits:9,val:229},{op:16,bits:7,val:7},{op:0,bits:8,val:90},{op:0,bits:8,val:26},{op:0,bits:9,val:149},{op:20,bits:7,val:67},{op:0,bits:8,val:122},{op:0,bits:8,val:58},{op:0,bits:9,val:213},{op:18,bits:7,val:19},{op:0,bits:8,val:106},{op:0,bits:8,val:42},{op:0,bits:9,val:181},{op:0,bits:8,val:10},{op:0,bits:8,val:138},{op:0,bits:8,val:74},{op:0,bits:9,val:245},{op:16,bits:7,val:5},{op:0,bits:8,val:86},{op:0,bits:8,val:22},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:118},{op:0,bits:8,val:54},{op:0,bits:9,val:205},{op:17,bits:7,val:15},{op:0,bits:8,val:102},{op:0,bits:8,val:38},{op:0,bits:9,val:173},{op:0,bits:8,val:6},{op:0,bits:8,val:134},{op:0,bits:8,val:70},{op:0,bits:9,val:237},{op:16,bits:7,val:9},{op:0,bits:8,val:94},{op:0,bits:8,val:30},{op:0,bits:9,val:157},{op:20,bits:7,val:99},{op:0,bits:8,val:126},{op:0,bits:8,val:62},{op:0,bits:9,val:221},{op:18,bits:7,val:27},{op:0,bits:8,val:110},{op:0,bits:8,val:46},{op:0,bits:9,val:189},{op:0,bits:8,val:14},{op:0,bits:8,val:142},{op:0,bits:8,val:78},{op:0,bits:9,val:253},{op:96,bits:7,val:0},{op:0,bits:8,val:81},{op:0,bits:8,val:17},{op:21,bits:8,val:131},{op:18,bits:7,val:31},{op:0,bits:8,val:113},{op:0,bits:8,val:49},{op:0,bits:9,val:195},{op:16,bits:7,val:10},{op:0,bits:8,val:97},{op:0,bits:8,val:33},{op:0,bits:9,val:163},{op:0,bits:8,val:1},{op:0,bits:8,val:129},{op:0,bits:8,val:65},{op:0,bits:9,val:227},{op:16,bits:7,val:6},{op:0,bits:8,val:89},{op:0,bits:8,val:25},{op:0,bits:9,val:147},{op:19,bits:7,val:59},{op:0,bits:8,val:121},{op:0,bits:8,val:57},{op:0,bits:9,val:211},{op:17,bits:7,val:17},{op:0,bits:8,val:105},{op:0,bits:8,val:41},{op:0,bits:9,val:179},{op:0,bits:8,val:9},{op:0,bits:8,val:137},{op:0,bits:8,val:73},{op:0,bits:9,val:243},{op:16,bits:7,val:4},{op:0,bits:8,val:85},{op:0,bits:8,val:21},{op:16,bits:8,val:258},{op:19,bits:7,val:43},{op:0,bits:8,val:117},{op:0,bits:8,val:53},{op:0,bits:9,val:203},{op:17,bits:7,val:13},{op:0,bits:8,val:101},{op:0,bits:8,val:37},{op:0,bits:9,val:171},{op:0,bits:8,val:5},{op:0,bits:8,val:133},{op:0,bits:8,val:69},{op:0,bits:9,val:235},{op:16,bits:7,val:8},{op:0,bits:8,val:93},{op:0,bits:8,val:29},{op:0,bits:9,val:155},{op:20,bits:7,val:83},{op:0,bits:8,val:125},{op:0,bits:8,val:61},{op:0,bits:9,val:219},{op:18,bits:7,val:23},{op:0,bits:8,val:109},{op:0,bits:8,val:45},{op:0,bits:9,val:187},{op:0,bits:8,val:13},{op:0,bits:8,val:141},{op:0,bits:8,val:77},{op:0,bits:9,val:251},{op:16,bits:7,val:3},{op:0,bits:8,val:83},{op:0,bits:8,val:19},{op:21,bits:8,val:195},{op:19,bits:7,val:35},{op:0,bits:8,val:115},{op:0,bits:8,val:51},{op:0,bits:9,val:199},{op:17,bits:7,val:11},{op:0,bits:8,val:99},{op:0,bits:8,val:35},{op:0,bits:9,val:167},{op:0,bits:8,val:3},{op:0,bits:8,val:131},{op:0,bits:8,val:67},{op:0,bits:9,val:231},{op:16,bits:7,val:7},{op:0,bits:8,val:91},{op:0,bits:8,val:27},{op:0,bits:9,val:151},{op:20,bits:7,val:67},{op:0,bits:8,val:123},{op:0,bits:8,val:59},{op:0,bits:9,val:215},{op:18,bits:7,val:19},{op:0,bits:8,val:107},{op:0,bits:8,val:43},{op:0,bits:9,val:183},{op:0,bits:8,val:11},{op:0,bits:8,val:139},{op:0,bits:8,val:75},{op:0,bits:9,val:247},{op:16,bits:7,val:5},{op:0,bits:8,val:87},{op:0,bits:8,val:23},{op:64,bits:8,val:0},{op:19,bits:7,val:51},{op:0,bits:8,val:119},{op:0,bits:8,val:55},{op:0,bits:9,val:207},{op:17,bits:7,val:15},{op:0,bits:8,val:103},{op:0,bits:8,val:39},{op:0,bits:9,val:175},{op:0,bits:8,val:7},{op:0,bits:8,val:135},{op:0,bits:8,val:71},{op:0,bits:9,val:239},{op:16,bits:7,val:9},{op:0,bits:8,val:95},{op:0,bits:8,val:31},{op:0,bits:9,val:159},{op:20,bits:7,val:99},{op:0,bits:8,val:127},{op:0,bits:8,val:63},{op:0,bits:9,val:223},{op:18,bits:7,val:27},{op:0,bits:8,val:111},{op:0,bits:8,val:47},{op:0,bits:9,val:191},{op:0,bits:8,val:15},{op:0,bits:8,val:143},{op:0,bits:8,val:79},{op:0,bits:9,val:255}],Q=Q||[{op:16,bits:5,val:1},{op:23,bits:5,val:257},{op:19,bits:5,val:17},{op:27,bits:5,val:4097},{op:17,bits:5,val:5},{op:25,bits:5,val:1025},{op:21,bits:5,val:65},{op:29,bits:5,val:16385},{op:16,bits:5,val:3},{op:24,bits:5,val:513},{op:20,bits:5,val:33},{op:28,bits:5,val:8193},{op:18,bits:5,val:9},{op:26,bits:5,val:2049},{op:22,bits:5,val:129},{op:64,bits:5,val:0},{op:16,bits:5,val:2},{op:23,bits:5,val:385},{op:19,bits:5,val:25},{op:27,bits:5,val:6145},{op:17,bits:5,val:7},{op:25,bits:5,val:1537},{op:21,bits:5,val:97},{op:29,bits:5,val:24577},{op:16,bits:5,val:4},{op:24,bits:5,val:769},{op:20,bits:5,val:49},{op:28,bits:5,val:12289},{op:18,bits:5,val:13},{op:26,bits:5,val:3073},{op:22,bits:5,val:193},{op:64,bits:5,val:0}],m.lencode=0,m.distcode=512,u=0;u<512;u++)m.codes[u]=J[u];for(u=0;u<32;u++)m.codes[u+512]=Q[u];if(m.lenbits=9,m.distbits=5,i.mode=19,a!=ZLIB.Z_TREES)break;st(s,2);break t;case 2:i.mode=16;break;case 3:t.msg="invalid block type",i.mode=q}st(s,2)}break;case 13:if(ot(s),!at(s,32))break t;if((65535&s.hold)!=(s.hold>>>16&65535^65535)){t.msg="invalid stored block lengths",i.mode=q;break}if(i.length=65535&s.hold,$(s),i.mode=14,a==ZLIB.Z_TREES)break t;case 14:i.mode=15;case 15:if(e=i.length){if(0==(e=(e=e>s.have?s.have:e)>s.left?s.left:e))break t;t.output_data+=t.input_data.substring(s.next,s.next+e),t.next_out+=e,s.have-=e,s.next+=e,s.left-=e,i.length-=e}else i.mode=Y;break;case 16:if(!at(s,14))break t;if(i.nlen=it(s,5)+257,st(s,5),i.ndist=it(s,5)+1,st(s,5),i.ncode=it(s,4)+4,st(s,4),286i.nlen+i.ndist){t.msg="invalid bit length repeat",i.mode=q;break}for(;e--;)i.lens[i.have++]=p}}if(i.mode==q)break;if(0==i.lens[256]){t.msg="invalid code -- missing end-of-block",i.mode=q;break}if(i.next=0,i.lencode=i.next,i.lenbits=9,n=G(i,1)){t.msg="invalid literal/lengths set",i.mode=q;break}if(i.distcode=i.next,i.distbits=6,n=G(i,2)){t.msg="invalid distances set",i.mode=q;break}if(i.mode=19,a==ZLIB.Z_TREES)break t;case 19:i.mode=20;case 20:if(6<=s.have&&258<=s.left){X(s),I=Z=y=g=k=_=P=U=j=H=T=O=C=z=N=F=D=S=K=A=E=R=B=L=x=w=void 0;var _,k,g,w=t,x=l,Z=-1,I=-1,L=w.state,B=w.input_data,R=w.next_in,E=R+w.avail_in-5,A=w.next_out,K=A-(x-w.avail_out),S=A+(w.avail_out-257),D=L.wsize,F=L.whave,N=L.wnext,z=L.window,C=L.hold,O=L.bits,T=L.codes,H=L.lencode,j=L.distcode,U=(1<>>=k=_.bits,O-=k,0==(k=_.op))w.output_data+=String.fromCharCode(_.val),A++;else{if(!(16&k)){if(0==(64&k)){_=T[H+(_.val+(C&(1<>>=k,O-=k),O<15&&(C+=(255&B.charCodeAt(R++))<>>=k=_.bits,O-=k,!(16&(k=_.op))){if(0==(64&k)){_=T[j+(_.val+(C&(1<>>=k,O-=k,(k=A-K)>>3)<<3))-1,w.next_in=R-=g,w.next_out=A,w.avail_in=R>>v.bits)],!(v.bits+b.bits<=s.bits);)if(!tt(s))break t;st(s,v.bits),i.back+=v.bits}if(st(s,b.bits),i.back+=b.bits,i.length=b.val,0==b.op){i.mode=25;break}if(32&b.op){i.back=-1,i.mode=Y;break}if(64&b.op){t.msg="invalid literal/length code",i.mode=q;break}i.extra=15&b.op,i.mode=21;case 21:if(i.extra){if(!at(s,i.extra))break t;i.length+=it(s,i.extra),st(s,i.extra),i.back+=i.extra}i.was=i.length,i.mode=22;case 22:for(;!((b=i.codes[i.distcode+it(s,i.distbits)]).bits<=s.bits);)if(!tt(s))break t;if(0==(240&b.op)){for(v=b;b=i.codes[i.distcode+v.val+(it(s,v.bits+v.op)>>>v.bits)],!(v.bits+b.bits<=s.bits);)if(!tt(s))break t;st(s,v.bits),i.back+=v.bits}if(st(s,b.bits),i.back+=b.bits,64&b.op){t.msg="invalid distance code",i.mode=q;break}i.offset=b.val,i.extra=15&b.op,i.mode=23;case 23:if(i.extra){if(!at(s,i.extra))break t;i.offset+=it(s,i.extra),st(s,i.extra),i.back+=i.extra}i.mode=24;case 24:if(0==s.left)break t;if(e=l-s.left,i.offset>e){if((e=i.offset-e)>i.whave&&i.sane){t.msg="invalid distance too far back",i.mode=q;break}f=(c=e>i.wnext?(e-=i.wnext,i.wsize-e):i.wnext-e,-1),e>i.length&&(e=i.length)}else c=-1,f=t.next_out-i.offset,e=i.length;if(e>s.left&&(e=s.left),s.left-=e,i.length-=e,0<=c)t.output_data+=i.window.substring(c,c+e),t.next_out+=e,e=0;else for(t.next_out+=e;t.output_data+=t.output_data.charAt(f++),--e;);0==i.length&&(i.mode=20);break;case 25:if(0==s.left)break t;t.output_data+=String.fromCharCode(i.length),t.next_out++,s.left--,i.mode=20;break;case 26:if(i.wrap){if(!at(s,32))break t;if(l-=s.left,t.total_out+=l,i.total+=l,l&&(t.adler=i.check=t.checksum_function(i.check,t.output_data,t.output_data.length-l,l)),l=s.left,(i.flags?s.hold:lt(s.hold))!=i.check){t.msg="incorrect data check",i.mode=q;break}$(s)}i.mode=27;case 27:if(i.wrap&&i.flags){if(!at(s,32))break t;if(s.hold!=(4294967295&i.total)){t.msg="incorrect length check",i.mode=q;break}$(s)}i.mode=28;case 28:n=ZLIB.Z_STREAM_END;break t;case q:n=ZLIB.Z_DATA_ERROR;break t;case 30:return ZLIB.Z_MEM_ERROR;default:return ZLIB.Z_STREAM_ERROR}return X(s),(i.wsize||l!=t.avail_out&&i.modecode{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/public/styles/bootstrap.css b/public/styles/bootstrap.css new file mode 100644 index 00000000..b7ab57f2 --- /dev/null +++ b/public/styles/bootstrap.css @@ -0,0 +1,12057 @@ +@charset "UTF-8"; +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +:root, +[data-bs-theme=light] { + --bs-blue: #0d6efd; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #d63384; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #198754; + --bs-teal: #20c997; + --bs-cyan: #0dcaf0; + --bs-black: #000; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #0d6efd; + --bs-secondary: #6c757d; + --bs-success: #198754; + --bs-info: #0dcaf0; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 13, 110, 253; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 25, 135, 84; + --bs-info-rgb: 13, 202, 240; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-primary-text-emphasis: #052c65; + --bs-secondary-text-emphasis: #2b2f32; + --bs-success-text-emphasis: #0a3622; + --bs-info-text-emphasis: #055160; + --bs-warning-text-emphasis: #664d03; + --bs-danger-text-emphasis: #58151c; + --bs-light-text-emphasis: #495057; + --bs-dark-text-emphasis: #495057; + --bs-primary-bg-subtle: #cfe2ff; + --bs-secondary-bg-subtle: #e2e3e5; + --bs-success-bg-subtle: #d1e7dd; + --bs-info-bg-subtle: #cff4fc; + --bs-warning-bg-subtle: #fff3cd; + --bs-danger-bg-subtle: #f8d7da; + --bs-light-bg-subtle: #fcfcfd; + --bs-dark-bg-subtle: #ced4da; + --bs-primary-border-subtle: #9ec5fe; + --bs-secondary-border-subtle: #c4c8cb; + --bs-success-border-subtle: #a3cfbb; + --bs-info-border-subtle: #9eeaf9; + --bs-warning-border-subtle: #ffe69c; + --bs-danger-border-subtle: #f1aeb5; + --bs-light-border-subtle: #e9ecef; + --bs-dark-border-subtle: #adb5bd; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-color-rgb: 33, 37, 41; + --bs-body-bg: #fff; + --bs-body-bg-rgb: 255, 255, 255; + --bs-emphasis-color: #000; + --bs-emphasis-color-rgb: 0, 0, 0; + --bs-secondary-color: rgba(33, 37, 41, 0.75); + --bs-secondary-color-rgb: 33, 37, 41; + --bs-secondary-bg: #e9ecef; + --bs-secondary-bg-rgb: 233, 236, 239; + --bs-tertiary-color: rgba(33, 37, 41, 0.5); + --bs-tertiary-color-rgb: 33, 37, 41; + --bs-tertiary-bg: #f8f9fa; + --bs-tertiary-bg-rgb: 248, 249, 250; + --bs-heading-color: inherit; + --bs-link-color: #0d6efd; + --bs-link-color-rgb: 13, 110, 253; + --bs-link-decoration: underline; + --bs-link-hover-color: #0a58ca; + --bs-link-hover-color-rgb: 10, 88, 202; + --bs-code-color: #d63384; + --bs-highlight-color: #212529; + --bs-highlight-bg: #fff3cd; + --bs-border-width: 1px; + --bs-border-style: solid; + --bs-border-color: #dee2e6; + --bs-border-color-translucent: rgba(0, 0, 0, 0.175); + --bs-border-radius: 0.375rem; + --bs-border-radius-sm: 0.25rem; + --bs-border-radius-lg: 0.5rem; + --bs-border-radius-xl: 1rem; + --bs-border-radius-xxl: 2rem; + --bs-border-radius-2xl: var(--bs-border-radius-xxl); + --bs-border-radius-pill: 50rem; + --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); + --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); + --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075); + --bs-focus-ring-width: 0.25rem; + --bs-focus-ring-opacity: 0.25; + --bs-focus-ring-color: rgba(13, 110, 253, 0.25); + --bs-form-valid-color: #198754; + --bs-form-valid-border-color: #198754; + --bs-form-invalid-color: #dc3545; + --bs-form-invalid-border-color: #dc3545; +} + +[data-bs-theme=dark] { + color-scheme: dark; + --bs-body-color: #dee2e6; + --bs-body-color-rgb: 222, 226, 230; + --bs-body-bg: #212529; + --bs-body-bg-rgb: 33, 37, 41; + --bs-emphasis-color: #fff; + --bs-emphasis-color-rgb: 255, 255, 255; + --bs-secondary-color: rgba(222, 226, 230, 0.75); + --bs-secondary-color-rgb: 222, 226, 230; + --bs-secondary-bg: #343a40; + --bs-secondary-bg-rgb: 52, 58, 64; + --bs-tertiary-color: rgba(222, 226, 230, 0.5); + --bs-tertiary-color-rgb: 222, 226, 230; + --bs-tertiary-bg: #2b3035; + --bs-tertiary-bg-rgb: 43, 48, 53; + --bs-primary-text-emphasis: #6ea8fe; + --bs-secondary-text-emphasis: #a7acb1; + --bs-success-text-emphasis: #75b798; + --bs-info-text-emphasis: #6edff6; + --bs-warning-text-emphasis: #ffda6a; + --bs-danger-text-emphasis: #ea868f; + --bs-light-text-emphasis: #f8f9fa; + --bs-dark-text-emphasis: #dee2e6; + --bs-primary-bg-subtle: #031633; + --bs-secondary-bg-subtle: #161719; + --bs-success-bg-subtle: #051b11; + --bs-info-bg-subtle: #032830; + --bs-warning-bg-subtle: #332701; + --bs-danger-bg-subtle: #2c0b0e; + --bs-light-bg-subtle: #343a40; + --bs-dark-bg-subtle: #1a1d20; + --bs-primary-border-subtle: #084298; + --bs-secondary-border-subtle: #41464b; + --bs-success-border-subtle: #0f5132; + --bs-info-border-subtle: #087990; + --bs-warning-border-subtle: #997404; + --bs-danger-border-subtle: #842029; + --bs-light-border-subtle: #495057; + --bs-dark-border-subtle: #343a40; + --bs-heading-color: inherit; + --bs-link-color: #6ea8fe; + --bs-link-hover-color: #8bb9fe; + --bs-link-color-rgb: 110, 168, 254; + --bs-link-hover-color-rgb: 139, 185, 254; + --bs-code-color: #e685b5; + --bs-highlight-color: #dee2e6; + --bs-highlight-bg: #664d03; + --bs-border-color: #495057; + --bs-border-color-translucent: rgba(255, 255, 255, 0.15); + --bs-form-valid-color: #75b798; + --bs-form-valid-border-color: #75b798; + --bs-form-invalid-color: #ea868f; + --bs-form-invalid-border-color: #ea868f; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + border: 0; + border-top: var(--bs-border-width) solid; + opacity: 0.25; +} + +h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; + color: var(--bs-heading-color); +} + +h1, .h1 { + font-size: calc(1.375rem + 1.5vw); +} +@media (min-width: 1200px) { + h1, .h1 { + font-size: 2.5rem; + } +} + +h2, .h2 { + font-size: calc(1.325rem + 0.9vw); +} +@media (min-width: 1200px) { + h2, .h2 { + font-size: 2rem; + } +} + +h3, .h3 { + font-size: calc(1.3rem + 0.6vw); +} +@media (min-width: 1200px) { + h3, .h3 { + font-size: 1.75rem; + } +} + +h4, .h4 { + font-size: calc(1.275rem + 0.3vw); +} +@media (min-width: 1200px) { + h4, .h4 { + font-size: 1.5rem; + } +} + +h5, .h5 { + font-size: 1.25rem; +} + +h6, .h6 { + font-size: 1rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title] { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 700; +} + +dd { + margin-bottom: 0.5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small, .small { + font-size: 0.875em; +} + +mark, .mark { + padding: 0.1875em; + color: var(--bs-highlight-color); + background-color: var(--bs-highlight-bg); +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +a { + color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); + text-decoration: underline; +} +a:hover { + --bs-link-color-rgb: var(--bs-link-hover-color-rgb); +} + +a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 0.875em; +} +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 0.875em; + color: var(--bs-code-color); + word-wrap: break-word; +} +a > code { + color: inherit; +} + +kbd { + padding: 0.1875rem 0.375rem; + font-size: 0.875em; + color: var(--bs-body-bg); + background-color: var(--bs-body-color); + border-radius: 0.25rem; +} +kbd kbd { + padding: 0; + font-size: 1em; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-secondary-color); + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +button { + border-radius: 0; +} + +button:focus:not(:focus-visible) { + outline: 0; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +select { + text-transform: none; +} + +[role=button] { + cursor: pointer; +} + +select { + word-wrap: normal; +} +select:disabled { + opacity: 1; +} + +[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { + display: none !important; +} + +button, +[type=button], +[type=reset], +[type=submit] { + -webkit-appearance: button; +} +button:not(:disabled), +[type=button]:not(:disabled), +[type=reset]:not(:disabled), +[type=submit]:not(:disabled) { + cursor: pointer; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: calc(1.275rem + 0.3vw); + line-height: inherit; +} +@media (min-width: 1200px) { + legend { + font-size: 1.5rem; + } +} +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type=search] { + -webkit-appearance: textfield; + outline-offset: -2px; +} + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +::file-selector-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + +.display-1 { + font-size: calc(1.625rem + 4.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-1 { + font-size: 5rem; + } +} + +.display-2 { + font-size: calc(1.575rem + 3.9vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-2 { + font-size: 4.5rem; + } +} + +.display-3 { + font-size: calc(1.525rem + 3.3vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-3 { + font-size: 4rem; + } +} + +.display-4 { + font-size: calc(1.475rem + 2.7vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-4 { + font-size: 3.5rem; + } +} + +.display-5 { + font-size: calc(1.425rem + 2.1vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-5 { + font-size: 3rem; + } +} + +.display-6 { + font-size: calc(1.375rem + 1.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-6 { + font-size: 2.5rem; + } +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 0.875em; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} +.blockquote > :last-child { + margin-bottom: 0; +} + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: 0.875em; + color: #6c757d; +} +.blockquote-footer::before { + content: "— "; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: var(--bs-body-bg); + border: var(--bs-border-width) solid var(--bs-border-color); + border-radius: var(--bs-border-radius); + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 0.875em; + color: var(--bs-secondary-color); +} + +.container, +.container-fluid, +.container-xxl, +.container-xl, +.container-lg, +.container-md, +.container-sm { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container-sm, .container { + max-width: 540px; + } +} +@media (min-width: 768px) { + .container-md, .container-sm, .container { + max-width: 720px; + } +} +@media (min-width: 992px) { + .container-lg, .container-md, .container-sm, .container { + max-width: 960px; + } +} +@media (min-width: 1200px) { + .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1140px; + } +} +@media (min-width: 1400px) { + .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1320px; + } +} +:root { + --bs-breakpoint-xs: 0; + --bs-breakpoint-sm: 576px; + --bs-breakpoint-md: 768px; + --bs-breakpoint-lg: 992px; + --bs-breakpoint-xl: 1200px; + --bs-breakpoint-xxl: 1400px; +} + +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); +} +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.33333333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333333%; +} + +.offset-2 { + margin-left: 16.66666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333333%; +} + +.offset-5 { + margin-left: 41.66666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333333%; +} + +.offset-8 { + margin-left: 66.66666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333333%; +} + +.offset-11 { + margin-left: 91.66666667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333333%; + } + .offset-sm-2 { + margin-left: 16.66666667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333333%; + } + .offset-sm-5 { + margin-left: 41.66666667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333333%; + } + .offset-sm-8 { + margin-left: 66.66666667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333333%; + } + .offset-sm-11 { + margin-left: 91.66666667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 3rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333333%; + } + .offset-md-2 { + margin-left: 16.66666667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333333%; + } + .offset-md-5 { + margin-left: 41.66666667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333333%; + } + .offset-md-8 { + margin-left: 66.66666667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333333%; + } + .offset-md-11 { + margin-left: 91.66666667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 3rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333333%; + } + .offset-lg-2 { + margin-left: 16.66666667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333333%; + } + .offset-lg-5 { + margin-left: 41.66666667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333333%; + } + .offset-lg-8 { + margin-left: 66.66666667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333333%; + } + .offset-lg-11 { + margin-left: 91.66666667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 3rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333333%; + } + .offset-xl-2 { + margin-left: 16.66666667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333333%; + } + .offset-xl-5 { + margin-left: 41.66666667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333333%; + } + .offset-xl-8 { + margin-left: 66.66666667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333333%; + } + .offset-xl-11 { + margin-left: 91.66666667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 3rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 3rem; + } +} +@media (min-width: 1400px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.33333333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-left: 0; + } + .offset-xxl-1 { + margin-left: 8.33333333%; + } + .offset-xxl-2 { + margin-left: 16.66666667%; + } + .offset-xxl-3 { + margin-left: 25%; + } + .offset-xxl-4 { + margin-left: 33.33333333%; + } + .offset-xxl-5 { + margin-left: 41.66666667%; + } + .offset-xxl-6 { + margin-left: 50%; + } + .offset-xxl-7 { + margin-left: 58.33333333%; + } + .offset-xxl-8 { + margin-left: 66.66666667%; + } + .offset-xxl-9 { + margin-left: 75%; + } + .offset-xxl-10 { + margin-left: 83.33333333%; + } + .offset-xxl-11 { + margin-left: 91.66666667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 3rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 3rem; + } +} +.table { + --bs-table-color-type: initial; + --bs-table-bg-type: initial; + --bs-table-color-state: initial; + --bs-table-bg-state: initial; + --bs-table-color: var(--bs-emphasis-color); + --bs-table-bg: var(--bs-body-bg); + --bs-table-border-color: var(--bs-border-color); + --bs-table-accent-bg: transparent; + --bs-table-striped-color: var(--bs-emphasis-color); + --bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05); + --bs-table-active-color: var(--bs-emphasis-color); + --bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1); + --bs-table-hover-color: var(--bs-emphasis-color); + --bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075); + width: 100%; + margin-bottom: 1rem; + vertical-align: top; + border-color: var(--bs-table-border-color); +} +.table > :not(caption) > * > * { + padding: 0.5rem 0.5rem; + color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color))); + background-color: var(--bs-table-bg); + border-bottom-width: var(--bs-border-width); + box-shadow: inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg))); +} +.table > tbody { + vertical-align: inherit; +} +.table > thead { + vertical-align: bottom; +} + +.table-group-divider { + border-top: calc(var(--bs-border-width) * 2) solid currentcolor; +} + +.caption-top { + caption-side: top; +} + +.table-sm > :not(caption) > * > * { + padding: 0.25rem 0.25rem; +} + +.table-bordered > :not(caption) > * { + border-width: var(--bs-border-width) 0; +} +.table-bordered > :not(caption) > * > * { + border-width: 0 var(--bs-border-width); +} + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0; +} +.table-borderless > :not(:first-child) { + border-top-width: 0; +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + --bs-table-color-type: var(--bs-table-striped-color); + --bs-table-bg-type: var(--bs-table-striped-bg); +} + +.table-striped-columns > :not(caption) > tr > :nth-child(even) { + --bs-table-color-type: var(--bs-table-striped-color); + --bs-table-bg-type: var(--bs-table-striped-bg); +} + +.table-active { + --bs-table-color-state: var(--bs-table-active-color); + --bs-table-bg-state: var(--bs-table-active-bg); +} + +.table-hover > tbody > tr:hover > * { + --bs-table-color-state: var(--bs-table-hover-color); + --bs-table-bg-state: var(--bs-table-hover-bg); +} + +.table-primary { + --bs-table-color: #000; + --bs-table-bg: #cfe2ff; + --bs-table-border-color: #a6b5cc; + --bs-table-striped-bg: #c5d7f2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bacbe6; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfd1ec; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-secondary { + --bs-table-color: #000; + --bs-table-bg: #e2e3e5; + --bs-table-border-color: #b5b6b7; + --bs-table-striped-bg: #d7d8da; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbccce; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d1d2d4; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-success { + --bs-table-color: #000; + --bs-table-bg: #d1e7dd; + --bs-table-border-color: #a7b9b1; + --bs-table-striped-bg: #c7dbd2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bcd0c7; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c1d6cc; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-info { + --bs-table-color: #000; + --bs-table-bg: #cff4fc; + --bs-table-border-color: #a6c3ca; + --bs-table-striped-bg: #c5e8ef; + --bs-table-striped-color: #000; + --bs-table-active-bg: #badce3; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bfe2e9; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-warning { + --bs-table-color: #000; + --bs-table-bg: #fff3cd; + --bs-table-border-color: #ccc2a4; + --bs-table-striped-bg: #f2e7c3; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e6dbb9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #ece1be; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-danger { + --bs-table-color: #000; + --bs-table-bg: #f8d7da; + --bs-table-border-color: #c6acae; + --bs-table-striped-bg: #eccccf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfc2c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5c7ca; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-light { + --bs-table-color: #000; + --bs-table-bg: #f8f9fa; + --bs-table-border-color: #c6c7c8; + --bs-table-striped-bg: #ecedee; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfe0e1; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5e6e7; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-dark { + --bs-table-color: #fff; + --bs-table-bg: #212529; + --bs-table-border-color: #4d5154; + --bs-table-striped-bg: #2c3034; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373b3e; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323539; + --bs-table-hover-color: #fff; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 767.98px) { + .table-responsive-md { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 991.98px) { + .table-responsive-lg { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 1199.98px) { + .table-responsive-xl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 1399.98px) { + .table-responsive-xxl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +.form-label { + margin-bottom: 0.5rem; +} + +.col-form-label { + padding-top: calc(0.375rem + var(--bs-border-width)); + padding-bottom: calc(0.375rem + var(--bs-border-width)); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.5rem + var(--bs-border-width)); + padding-bottom: calc(0.5rem + var(--bs-border-width)); + font-size: 1.25rem; +} + +.col-form-label-sm { + padding-top: calc(0.25rem + var(--bs-border-width)); + padding-bottom: calc(0.25rem + var(--bs-border-width)); + font-size: 0.875rem; +} + +.form-text { + margin-top: 0.25rem; + font-size: 0.875em; + color: var(--bs-secondary-color); +} + +.form-control { + display: block; + width: 100%; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: var(--bs-body-bg); + background-clip: padding-box; + border: var(--bs-border-width) solid var(--bs-border-color); + border-radius: var(--bs-border-radius); + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} +.form-control[type=file] { + overflow: hidden; +} +.form-control[type=file]:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control:focus { + color: var(--bs-body-color); + background-color: var(--bs-body-bg); + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-control::-webkit-date-and-time-value { + min-width: 85px; + height: 1.5em; + margin: 0; +} +.form-control::-webkit-datetime-edit { + display: block; + padding: 0; +} +.form-control::-moz-placeholder { + color: var(--bs-secondary-color); + opacity: 1; +} +.form-control::placeholder { + color: var(--bs-secondary-color); + opacity: 1; +} +.form-control:disabled { + background-color: var(--bs-secondary-bg); + opacity: 1; +} +.form-control::-webkit-file-upload-button { + padding: 0.375rem 0.75rem; + margin: -0.375rem -0.75rem; + -webkit-margin-end: 0.75rem; + margin-inline-end: 0.75rem; + color: var(--bs-body-color); + background-color: var(--bs-tertiary-bg); + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: var(--bs-border-width); + border-radius: 0; + -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.form-control::file-selector-button { + padding: 0.375rem 0.75rem; + margin: -0.375rem -0.75rem; + -webkit-margin-end: 0.75rem; + margin-inline-end: 0.75rem; + color: var(--bs-body-color); + background-color: var(--bs-tertiary-bg); + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: var(--bs-border-width); + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control::-webkit-file-upload-button { + -webkit-transition: none; + transition: none; + } + .form-control::file-selector-button { + transition: none; + } +} +.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { + background-color: var(--bs-secondary-bg); +} +.form-control:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: var(--bs-secondary-bg); +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.375rem 0; + margin-bottom: 0; + line-height: 1.5; + color: var(--bs-body-color); + background-color: transparent; + border: solid transparent; + border-width: var(--bs-border-width) 0; +} +.form-control-plaintext:focus { + outline: 0; +} +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2)); + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + border-radius: var(--bs-border-radius-sm); +} +.form-control-sm::-webkit-file-upload-button { + padding: 0.25rem 0.5rem; + margin: -0.25rem -0.5rem; + -webkit-margin-end: 0.5rem; + margin-inline-end: 0.5rem; +} +.form-control-sm::file-selector-button { + padding: 0.25rem 0.5rem; + margin: -0.25rem -0.5rem; + -webkit-margin-end: 0.5rem; + margin-inline-end: 0.5rem; +} + +.form-control-lg { + min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2)); + padding: 0.5rem 1rem; + font-size: 1.25rem; + border-radius: var(--bs-border-radius-lg); +} +.form-control-lg::-webkit-file-upload-button { + padding: 0.5rem 1rem; + margin: -0.5rem -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem; +} +.form-control-lg::file-selector-button { + padding: 0.5rem 1rem; + margin: -0.5rem -1rem; + -webkit-margin-end: 1rem; + margin-inline-end: 1rem; +} + +textarea.form-control { + min-height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2)); +} +textarea.form-control-sm { + min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2)); +} +textarea.form-control-lg { + min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2)); +} + +.form-control-color { + width: 3rem; + height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2)); + padding: 0.375rem; +} +.form-control-color:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control-color::-moz-color-swatch { + border: 0 !important; + border-radius: var(--bs-border-radius); +} +.form-control-color::-webkit-color-swatch { + border: 0 !important; + border-radius: var(--bs-border-radius); +} +.form-control-color.form-control-sm { + height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2)); +} +.form-control-color.form-control-lg { + height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2)); +} + +.form-select { + --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + display: block; + width: 100%; + padding: 0.375rem 2.25rem 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: var(--bs-body-bg); + background-image: var(--bs-form-select-bg-img), var(--bs-form-select-bg-icon, none); + background-repeat: no-repeat; + background-position: right 0.75rem center; + background-size: 16px 12px; + border: var(--bs-border-width) solid var(--bs-border-color); + border-radius: var(--bs-border-radius); + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-select { + transition: none; + } +} +.form-select:focus { + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-select[multiple], .form-select[size]:not([size="1"]) { + padding-right: 0.75rem; + background-image: none; +} +.form-select:disabled { + background-color: var(--bs-secondary-bg); +} +.form-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 var(--bs-body-color); +} + +.form-select-sm { + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + font-size: 0.875rem; + border-radius: var(--bs-border-radius-sm); +} + +.form-select-lg { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + font-size: 1.25rem; + border-radius: var(--bs-border-radius-lg); +} + +[data-bs-theme=dark] .form-select { + --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); +} + +.form-check { + display: block; + min-height: 1.5rem; + padding-left: 1.5em; + margin-bottom: 0.125rem; +} +.form-check .form-check-input { + float: left; + margin-left: -1.5em; +} + +.form-check-reverse { + padding-right: 1.5em; + padding-left: 0; + text-align: right; +} +.form-check-reverse .form-check-input { + float: right; + margin-right: -1.5em; + margin-left: 0; +} + +.form-check-input { + --bs-form-check-bg: var(--bs-body-bg); + flex-shrink: 0; + width: 1em; + height: 1em; + margin-top: 0.25em; + vertical-align: top; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: var(--bs-form-check-bg); + background-image: var(--bs-form-check-bg-image); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: var(--bs-border-width) solid var(--bs-border-color); + -webkit-print-color-adjust: exact; + color-adjust: exact; + print-color-adjust: exact; +} +.form-check-input[type=checkbox] { + border-radius: 0.25em; +} +.form-check-input[type=radio] { + border-radius: 50%; +} +.form-check-input:active { + filter: brightness(90%); +} +.form-check-input:focus { + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-check-input:checked { + background-color: #0d6efd; + border-color: #0d6efd; +} +.form-check-input:checked[type=checkbox] { + --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); +} +.form-check-input:checked[type=radio] { + --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); +} +.form-check-input[type=checkbox]:indeterminate { + background-color: #0d6efd; + border-color: #0d6efd; + --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); +} +.form-check-input:disabled { + pointer-events: none; + filter: none; + opacity: 0.5; +} +.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { + cursor: default; + opacity: 0.5; +} + +.form-switch { + padding-left: 2.5em; +} +.form-switch .form-check-input { + --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); + width: 2em; + margin-left: -2.5em; + background-image: var(--bs-form-switch-bg); + background-position: left center; + border-radius: 2em; + transition: background-position 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-switch .form-check-input { + transition: none; + } +} +.form-switch .form-check-input:focus { + --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e"); +} +.form-switch .form-check-input:checked { + background-position: right center; + --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} +.form-switch.form-check-reverse { + padding-right: 2.5em; + padding-left: 0; +} +.form-switch.form-check-reverse .form-check-input { + margin-right: -2.5em; + margin-left: 0; +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.btn-check[disabled] + .btn, .btn-check:disabled + .btn { + pointer-events: none; + filter: none; + opacity: 0.65; +} + +[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus) { + --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e"); +} + +.form-range { + width: 100%; + height: 1.5rem; + padding: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: transparent; +} +.form-range:focus { + outline: 0; +} +.form-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-range::-moz-focus-outer { + border: 0; +} +.form-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + -webkit-appearance: none; + appearance: none; + background-color: #0d6efd; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none; + } +} +.form-range::-webkit-slider-thumb:active { + background-color: #b6d4fe; +} +.form-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: var(--bs-secondary-bg); + border-color: transparent; + border-radius: 1rem; +} +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + -moz-appearance: none; + appearance: none; + background-color: #0d6efd; + border: 0; + border-radius: 1rem; + -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-range::-moz-range-thumb { + -moz-transition: none; + transition: none; + } +} +.form-range::-moz-range-thumb:active { + background-color: #b6d4fe; +} +.form-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: var(--bs-secondary-bg); + border-color: transparent; + border-radius: 1rem; +} +.form-range:disabled { + pointer-events: none; +} +.form-range:disabled::-webkit-slider-thumb { + background-color: var(--bs-secondary-color); +} +.form-range:disabled::-moz-range-thumb { + background-color: var(--bs-secondary-color); +} + +.form-floating { + position: relative; +} +.form-floating > .form-control, +.form-floating > .form-control-plaintext, +.form-floating > .form-select { + height: calc(3.5rem + calc(var(--bs-border-width) * 2)); + min-height: calc(3.5rem + calc(var(--bs-border-width) * 2)); + line-height: 1.25; +} +.form-floating > label { + position: absolute; + top: 0; + left: 0; + z-index: 2; + height: 100%; + padding: 1rem 0.75rem; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + border: var(--bs-border-width) solid transparent; + transform-origin: 0 0; + transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-floating > label { + transition: none; + } +} +.form-floating > .form-control, +.form-floating > .form-control-plaintext { + padding: 1rem 0.75rem; +} +.form-floating > .form-control::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder { + color: transparent; +} +.form-floating > .form-control::placeholder, +.form-floating > .form-control-plaintext::placeholder { + color: transparent; +} +.form-floating > .form-control:not(:-moz-placeholder-shown), .form-floating > .form-control-plaintext:not(:-moz-placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown), +.form-floating > .form-control-plaintext:focus, +.form-floating > .form-control-plaintext:not(:placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:-webkit-autofill, +.form-floating > .form-control-plaintext:-webkit-autofill { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-select { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label { + color: rgba(var(--bs-body-color-rgb), 0.65); + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control:focus ~ label, +.form-floating > .form-control:not(:placeholder-shown) ~ label, +.form-floating > .form-control-plaintext ~ label, +.form-floating > .form-select ~ label { + color: rgba(var(--bs-body-color-rgb), 0.65); + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label::after { + position: absolute; + inset: 1rem 0.375rem; + z-index: -1; + height: 1.5em; + content: ""; + background-color: var(--bs-body-bg); + border-radius: var(--bs-border-radius); +} +.form-floating > .form-control:focus ~ label::after, +.form-floating > .form-control:not(:placeholder-shown) ~ label::after, +.form-floating > .form-control-plaintext ~ label::after, +.form-floating > .form-select ~ label::after { + position: absolute; + inset: 1rem 0.375rem; + z-index: -1; + height: 1.5em; + content: ""; + background-color: var(--bs-body-bg); + border-radius: var(--bs-border-radius); +} +.form-floating > .form-control:-webkit-autofill ~ label { + color: rgba(var(--bs-body-color-rgb), 0.65); + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control-plaintext ~ label { + border-width: var(--bs-border-width) 0; +} +.form-floating > :disabled ~ label, +.form-floating > .form-control:disabled ~ label { + color: #6c757d; +} +.form-floating > :disabled ~ label::after, +.form-floating > .form-control:disabled ~ label::after { + background-color: var(--bs-secondary-bg); +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} +.input-group > .form-control, +.input-group > .form-select, +.input-group > .form-floating { + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0; +} +.input-group > .form-control:focus, +.input-group > .form-select:focus, +.input-group > .form-floating:focus-within { + z-index: 5; +} +.input-group .btn { + position: relative; + z-index: 2; +} +.input-group .btn:focus { + z-index: 5; +} + +.input-group-text { + display: flex; + align-items: center; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + text-align: center; + white-space: nowrap; + background-color: var(--bs-tertiary-bg); + border: var(--bs-border-width) solid var(--bs-border-color); + border-radius: var(--bs-border-radius); +} + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: 0.5rem 1rem; + font-size: 1.25rem; + border-radius: var(--bs-border-radius-lg); +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + border-radius: var(--bs-border-radius-sm); +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: 3rem; +} + +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3), +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4), +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: calc(var(--bs-border-width) * -1); + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group > .form-floating:not(:first-child) > .form-control, +.input-group > .form-floating:not(:first-child) > .form-select { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: var(--bs-form-valid-color); +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: var(--bs-success); + border-radius: var(--bs-border-radius); +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: var(--bs-form-valid-border-color); + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: var(--bs-form-valid-border-color); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25); +} + +.was-validated textarea.form-control:valid, textarea.form-control.is-valid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .form-select:valid, .form-select.is-valid { + border-color: var(--bs-form-valid-border-color); +} +.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"] { + --bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + padding-right: 4.125rem; + background-position: right 0.75rem center, center right 2.25rem; + background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-select:valid:focus, .form-select.is-valid:focus { + border-color: var(--bs-form-valid-border-color); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25); +} + +.was-validated .form-control-color:valid, .form-control-color.is-valid { + width: calc(3rem + calc(1.5em + 0.75rem)); +} + +.was-validated .form-check-input:valid, .form-check-input.is-valid { + border-color: var(--bs-form-valid-border-color); +} +.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { + background-color: var(--bs-form-valid-color); +} +.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { + box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25); +} +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: var(--bs-form-valid-color); +} + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid, +.was-validated .input-group > .form-select:not(:focus):valid, +.input-group > .form-select:not(:focus).is-valid, +.was-validated .input-group > .form-floating:not(:focus-within):valid, +.input-group > .form-floating:not(:focus-within).is-valid { + z-index: 3; +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: var(--bs-form-invalid-color); +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: var(--bs-danger); + border-radius: var(--bs-border-radius); +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: var(--bs-form-invalid-border-color); + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: var(--bs-form-invalid-border-color); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25); +} + +.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.was-validated .form-select:invalid, .form-select.is-invalid { + border-color: var(--bs-form-invalid-border-color); +} +.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"] { + --bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + padding-right: 4.125rem; + background-position: right 0.75rem center, center right 2.25rem; + background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} +.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { + border-color: var(--bs-form-invalid-border-color); + box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25); +} + +.was-validated .form-control-color:invalid, .form-control-color.is-invalid { + width: calc(3rem + calc(1.5em + 0.75rem)); +} + +.was-validated .form-check-input:invalid, .form-check-input.is-invalid { + border-color: var(--bs-form-invalid-border-color); +} +.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { + background-color: var(--bs-form-invalid-color); +} +.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { + box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25); +} +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: var(--bs-form-invalid-color); +} + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid, +.was-validated .input-group > .form-select:not(:focus):invalid, +.input-group > .form-select:not(:focus).is-invalid, +.was-validated .input-group > .form-floating:not(:focus-within):invalid, +.input-group > .form-floating:not(:focus-within).is-invalid { + z-index: 4; +} + +.btn { + --bs-btn-padding-x: 0.75rem; + --bs-btn-padding-y: 0.375rem; + --bs-btn-font-family: ; + --bs-btn-font-size: 1rem; + --bs-btn-font-weight: 400; + --bs-btn-line-height: 1.5; + --bs-btn-color: var(--bs-body-color); + --bs-btn-bg: transparent; + --bs-btn-border-width: var(--bs-border-width); + --bs-btn-border-color: transparent; + --bs-btn-border-radius: var(--bs-border-radius); + --bs-btn-hover-border-color: transparent; + --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); + --bs-btn-disabled-opacity: 0.65; + --bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5); + display: inline-block; + padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x); + font-family: var(--bs-btn-font-family); + font-size: var(--bs-btn-font-size); + font-weight: var(--bs-btn-font-weight); + line-height: var(--bs-btn-line-height); + color: var(--bs-btn-color); + text-align: center; + text-decoration: none; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); + border-radius: var(--bs-btn-border-radius); + background-color: var(--bs-btn-bg); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} +.btn:hover { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); +} +.btn-check + .btn:hover { + color: var(--bs-btn-color); + background-color: var(--bs-btn-bg); + border-color: var(--bs-btn-border-color); +} +.btn:focus-visible { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:focus-visible + .btn { + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, .btn.active, .btn.show { + color: var(--bs-btn-active-color); + background-color: var(--bs-btn-active-bg); + border-color: var(--bs-btn-active-border-color); +} +.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible { + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:checked:focus-visible + .btn { + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn:disabled, .btn.disabled, fieldset:disabled .btn { + color: var(--bs-btn-disabled-color); + pointer-events: none; + background-color: var(--bs-btn-disabled-bg); + border-color: var(--bs-btn-disabled-border-color); + opacity: var(--bs-btn-disabled-opacity); +} + +.btn-primary { + --bs-btn-color: #fff; + --bs-btn-bg: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0b5ed7; + --bs-btn-hover-border-color: #0a58ca; + --bs-btn-focus-shadow-rgb: 49, 132, 253; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0a58ca; + --bs-btn-active-border-color: #0a53be; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #0d6efd; + --bs-btn-disabled-border-color: #0d6efd; +} + +.btn-secondary { + --bs-btn-color: #fff; + --bs-btn-bg: #6c757d; + --bs-btn-border-color: #6c757d; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #5c636a; + --bs-btn-hover-border-color: #565e64; + --bs-btn-focus-shadow-rgb: 130, 138, 145; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #565e64; + --bs-btn-active-border-color: #51585e; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #6c757d; + --bs-btn-disabled-border-color: #6c757d; +} + +.btn-success { + --bs-btn-color: #fff; + --bs-btn-bg: #198754; + --bs-btn-border-color: #198754; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #157347; + --bs-btn-hover-border-color: #146c43; + --bs-btn-focus-shadow-rgb: 60, 153, 110; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #146c43; + --bs-btn-active-border-color: #13653f; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #198754; + --bs-btn-disabled-border-color: #198754; +} + +.btn-info { + --bs-btn-color: #000; + --bs-btn-bg: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #31d2f2; + --bs-btn-hover-border-color: #25cff2; + --bs-btn-focus-shadow-rgb: 11, 172, 204; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #3dd5f3; + --bs-btn-active-border-color: #25cff2; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #0dcaf0; + --bs-btn-disabled-border-color: #0dcaf0; +} + +.btn-warning { + --bs-btn-color: #000; + --bs-btn-bg: #ffc107; + --bs-btn-border-color: #ffc107; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #ffca2c; + --bs-btn-hover-border-color: #ffc720; + --bs-btn-focus-shadow-rgb: 217, 164, 6; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #ffcd39; + --bs-btn-active-border-color: #ffc720; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #ffc107; + --bs-btn-disabled-border-color: #ffc107; +} + +.btn-danger { + --bs-btn-color: #fff; + --bs-btn-bg: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #bb2d3b; + --bs-btn-hover-border-color: #b02a37; + --bs-btn-focus-shadow-rgb: 225, 83, 97; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #b02a37; + --bs-btn-active-border-color: #a52834; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #dc3545; + --bs-btn-disabled-border-color: #dc3545; +} + +.btn-light { + --bs-btn-color: #000; + --bs-btn-bg: #f8f9fa; + --bs-btn-border-color: #f8f9fa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #d3d4d5; + --bs-btn-hover-border-color: #c6c7c8; + --bs-btn-focus-shadow-rgb: 211, 212, 213; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #c6c7c8; + --bs-btn-active-border-color: #babbbc; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f8f9fa; + --bs-btn-disabled-border-color: #f8f9fa; +} + +.btn-dark { + --bs-btn-color: #fff; + --bs-btn-bg: #212529; + --bs-btn-border-color: #212529; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #424649; + --bs-btn-hover-border-color: #373b3e; + --bs-btn-focus-shadow-rgb: 66, 70, 73; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #4d5154; + --bs-btn-active-border-color: #373b3e; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #212529; + --bs-btn-disabled-border-color: #212529; +} + +.btn-outline-primary { + --bs-btn-color: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0d6efd; + --bs-btn-hover-border-color: #0d6efd; + --bs-btn-focus-shadow-rgb: 13, 110, 253; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0d6efd; + --bs-btn-active-border-color: #0d6efd; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0d6efd; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0d6efd; + --bs-gradient: none; +} + +.btn-outline-secondary { + --bs-btn-color: #6c757d; + --bs-btn-border-color: #6c757d; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #6c757d; + --bs-btn-hover-border-color: #6c757d; + --bs-btn-focus-shadow-rgb: 108, 117, 125; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #6c757d; + --bs-btn-active-border-color: #6c757d; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #6c757d; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #6c757d; + --bs-gradient: none; +} + +.btn-outline-success { + --bs-btn-color: #198754; + --bs-btn-border-color: #198754; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #198754; + --bs-btn-hover-border-color: #198754; + --bs-btn-focus-shadow-rgb: 25, 135, 84; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #198754; + --bs-btn-active-border-color: #198754; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #198754; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #198754; + --bs-gradient: none; +} + +.btn-outline-info { + --bs-btn-color: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #0dcaf0; + --bs-btn-hover-border-color: #0dcaf0; + --bs-btn-focus-shadow-rgb: 13, 202, 240; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #0dcaf0; + --bs-btn-active-border-color: #0dcaf0; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0dcaf0; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0dcaf0; + --bs-gradient: none; +} + +.btn-outline-warning { + --bs-btn-color: #ffc107; + --bs-btn-border-color: #ffc107; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #ffc107; + --bs-btn-hover-border-color: #ffc107; + --bs-btn-focus-shadow-rgb: 255, 193, 7; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #ffc107; + --bs-btn-active-border-color: #ffc107; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #ffc107; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #ffc107; + --bs-gradient: none; +} + +.btn-outline-danger { + --bs-btn-color: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #dc3545; + --bs-btn-hover-border-color: #dc3545; + --bs-btn-focus-shadow-rgb: 220, 53, 69; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #dc3545; + --bs-btn-active-border-color: #dc3545; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #dc3545; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dc3545; + --bs-gradient: none; +} + +.btn-outline-light { + --bs-btn-color: #f8f9fa; + --bs-btn-border-color: #f8f9fa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f8f9fa; + --bs-btn-hover-border-color: #f8f9fa; + --bs-btn-focus-shadow-rgb: 248, 249, 250; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f8f9fa; + --bs-btn-active-border-color: #f8f9fa; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f8f9fa; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f8f9fa; + --bs-gradient: none; +} + +.btn-outline-dark { + --bs-btn-color: #212529; + --bs-btn-border-color: #212529; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #212529; + --bs-btn-hover-border-color: #212529; + --bs-btn-focus-shadow-rgb: 33, 37, 41; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #212529; + --bs-btn-active-border-color: #212529; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #212529; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #212529; + --bs-gradient: none; +} + +.btn-link { + --bs-btn-font-weight: 400; + --bs-btn-color: var(--bs-link-color); + --bs-btn-bg: transparent; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: var(--bs-link-hover-color); + --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: var(--bs-link-hover-color); + --bs-btn-active-border-color: transparent; + --bs-btn-disabled-color: #6c757d; + --bs-btn-disabled-border-color: transparent; + --bs-btn-box-shadow: 0 0 0 #000; + --bs-btn-focus-shadow-rgb: 49, 132, 253; + text-decoration: underline; +} +.btn-link:focus-visible { + color: var(--bs-btn-color); +} +.btn-link:hover { + color: var(--bs-btn-hover-color); +} + +.btn-lg, .btn-group-lg > .btn { + --bs-btn-padding-y: 0.5rem; + --bs-btn-padding-x: 1rem; + --bs-btn-font-size: 1.25rem; + --bs-btn-border-radius: var(--bs-border-radius-lg); +} + +.btn-sm, .btn-group-sm > .btn { + --bs-btn-padding-y: 0.25rem; + --bs-btn-padding-x: 0.5rem; + --bs-btn-font-size: 0.875rem; + --bs-btn-border-radius: var(--bs-border-radius-sm); +} + +.fade { + transition: opacity 0.15s linear; +} +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing.collapse-horizontal { + transition: none; + } +} + +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + --bs-dropdown-zindex: 1000; + --bs-dropdown-min-width: 10rem; + --bs-dropdown-padding-x: 0; + --bs-dropdown-padding-y: 0.5rem; + --bs-dropdown-spacer: 0.125rem; + --bs-dropdown-font-size: 1rem; + --bs-dropdown-color: var(--bs-body-color); + --bs-dropdown-bg: var(--bs-body-bg); + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-border-radius: var(--bs-border-radius); + --bs-dropdown-border-width: var(--bs-border-width); + --bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width)); + --bs-dropdown-divider-bg: var(--bs-border-color-translucent); + --bs-dropdown-divider-margin-y: 0.5rem; + --bs-dropdown-box-shadow: var(--bs-box-shadow); + --bs-dropdown-link-color: var(--bs-body-color); + --bs-dropdown-link-hover-color: var(--bs-body-color); + --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg); + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #0d6efd; + --bs-dropdown-link-disabled-color: var(--bs-tertiary-color); + --bs-dropdown-item-padding-x: 1rem; + --bs-dropdown-item-padding-y: 0.25rem; + --bs-dropdown-header-color: #6c757d; + --bs-dropdown-header-padding-x: 1rem; + --bs-dropdown-header-padding-y: 0.5rem; + position: absolute; + z-index: var(--bs-dropdown-zindex); + display: none; + min-width: var(--bs-dropdown-min-width); + padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x); + margin: 0; + font-size: var(--bs-dropdown-font-size); + color: var(--bs-dropdown-color); + text-align: left; + list-style: none; + background-color: var(--bs-dropdown-bg); + background-clip: padding-box; + border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color); + border-radius: var(--bs-dropdown-border-radius); +} +.dropdown-menu[data-bs-popper] { + top: 100%; + left: 0; + margin-top: var(--bs-dropdown-spacer); +} + +.dropdown-menu-start { + --bs-position: start; +} +.dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0; +} + +.dropdown-menu-end { + --bs-position: end; +} +.dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-start { + --bs-position: start; + } + .dropdown-menu-sm-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-sm-end { + --bs-position: end; + } + .dropdown-menu-sm-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 768px) { + .dropdown-menu-md-start { + --bs-position: start; + } + .dropdown-menu-md-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-md-end { + --bs-position: end; + } + .dropdown-menu-md-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 992px) { + .dropdown-menu-lg-start { + --bs-position: start; + } + .dropdown-menu-lg-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-lg-end { + --bs-position: end; + } + .dropdown-menu-lg-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 1200px) { + .dropdown-menu-xl-start { + --bs-position: start; + } + .dropdown-menu-xl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xl-end { + --bs-position: end; + } + .dropdown-menu-xl-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 1400px) { + .dropdown-menu-xxl-start { + --bs-position: start; + } + .dropdown-menu-xxl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xxl-end { + --bs-position: end; + } + .dropdown-menu-xxl-end[data-bs-popper] { + right: 0; + left: auto; + } +} +.dropup .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: var(--bs-dropdown-spacer); +} +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--bs-dropdown-spacer); +} +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} +.dropend .dropdown-toggle:empty::after { + margin-left: 0; +} +.dropend .dropdown-toggle::after { + vertical-align: 0; +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: var(--bs-dropdown-spacer); +} +.dropstart .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} +.dropstart .dropdown-toggle::after { + display: none; +} +.dropstart .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} +.dropstart .dropdown-toggle:empty::after { + margin-left: 0; +} +.dropstart .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-divider { + height: 0; + margin: var(--bs-dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--bs-dropdown-divider-bg); + opacity: 1; +} + +.dropdown-item { + display: block; + width: 100%; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + clear: both; + font-weight: 400; + color: var(--bs-dropdown-link-color); + text-align: inherit; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border: 0; + border-radius: var(--bs-dropdown-item-border-radius, 0); +} +.dropdown-item:hover, .dropdown-item:focus { + color: var(--bs-dropdown-link-hover-color); + background-color: var(--bs-dropdown-link-hover-bg); +} +.dropdown-item.active, .dropdown-item:active { + color: var(--bs-dropdown-link-active-color); + text-decoration: none; + background-color: var(--bs-dropdown-link-active-bg); +} +.dropdown-item.disabled, .dropdown-item:disabled { + color: var(--bs-dropdown-link-disabled-color); + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x); + margin-bottom: 0; + font-size: 0.875rem; + color: var(--bs-dropdown-header-color); + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + color: var(--bs-dropdown-link-color); +} + +.dropdown-menu-dark { + --bs-dropdown-color: #dee2e6; + --bs-dropdown-bg: #343a40; + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-box-shadow: ; + --bs-dropdown-link-color: #dee2e6; + --bs-dropdown-link-hover-color: #fff; + --bs-dropdown-divider-bg: var(--bs-border-color-translucent); + --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15); + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #0d6efd; + --bs-dropdown-link-disabled-color: #adb5bd; + --bs-dropdown-header-color: #adb5bd; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + flex: 1 1 auto; +} +.btn-group > .btn-check:checked + .btn, +.btn-group > .btn-check:focus + .btn, +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn-check:checked + .btn, +.btn-group-vertical > .btn-check:focus + .btn, +.btn-group-vertical > .btn:hover, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.btn-toolbar .input-group { + width: auto; +} + +.btn-group { + border-radius: var(--bs-border-radius); +} +.btn-group > :not(.btn-check:first-child) + .btn, +.btn-group > .btn-group:not(:first-child) { + margin-left: calc(var(--bs-border-width) * -1); +} +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn.dropdown-toggle-split:first-child, +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:nth-child(n+3), +.btn-group > :not(.btn-check) + .btn, +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} +.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after { + margin-left: 0; +} +.dropstart .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: calc(var(--bs-border-width) * -1); +} +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn ~ .btn, +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav { + --bs-nav-link-padding-x: 1rem; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-link-color); + --bs-nav-link-hover-color: var(--bs-link-hover-color); + --bs-nav-link-disabled-color: var(--bs-secondary-color); + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x); + font-size: var(--bs-nav-link-font-size); + font-weight: var(--bs-nav-link-font-weight); + color: var(--bs-nav-link-color); + text-decoration: none; + background: none; + border: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .nav-link { + transition: none; + } +} +.nav-link:hover, .nav-link:focus { + color: var(--bs-nav-link-hover-color); +} +.nav-link:focus-visible { + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.nav-link.disabled, .nav-link:disabled { + color: var(--bs-nav-link-disabled-color); + pointer-events: none; + cursor: default; +} + +.nav-tabs { + --bs-nav-tabs-border-width: var(--bs-border-width); + --bs-nav-tabs-border-color: var(--bs-border-color); + --bs-nav-tabs-border-radius: var(--bs-border-radius); + --bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color); + --bs-nav-tabs-link-active-color: var(--bs-emphasis-color); + --bs-nav-tabs-link-active-bg: var(--bs-body-bg); + --bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg); + border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color); +} +.nav-tabs .nav-link { + margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width)); + border: var(--bs-nav-tabs-border-width) solid transparent; + border-top-left-radius: var(--bs-nav-tabs-border-radius); + border-top-right-radius: var(--bs-nav-tabs-border-radius); +} +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + isolation: isolate; + border-color: var(--bs-nav-tabs-link-hover-border-color); +} +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: var(--bs-nav-tabs-link-active-color); + background-color: var(--bs-nav-tabs-link-active-bg); + border-color: var(--bs-nav-tabs-link-active-border-color); +} +.nav-tabs .dropdown-menu { + margin-top: calc(-1 * var(--bs-nav-tabs-border-width)); + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills { + --bs-nav-pills-border-radius: var(--bs-border-radius); + --bs-nav-pills-link-active-color: #fff; + --bs-nav-pills-link-active-bg: #0d6efd; +} +.nav-pills .nav-link { + border-radius: var(--bs-nav-pills-border-radius); +} +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: var(--bs-nav-pills-link-active-color); + background-color: var(--bs-nav-pills-link-active-bg); +} + +.nav-underline { + --bs-nav-underline-gap: 1rem; + --bs-nav-underline-border-width: 0.125rem; + --bs-nav-underline-link-active-color: var(--bs-emphasis-color); + gap: var(--bs-nav-underline-gap); +} +.nav-underline .nav-link { + padding-right: 0; + padding-left: 0; + border-bottom: var(--bs-nav-underline-border-width) solid transparent; +} +.nav-underline .nav-link:hover, .nav-underline .nav-link:focus { + border-bottom-color: currentcolor; +} +.nav-underline .nav-link.active, +.nav-underline .show > .nav-link { + font-weight: 700; + color: var(--bs-nav-underline-link-active-color); + border-bottom-color: currentcolor; +} + +.nav-fill > .nav-link, +.nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; +} + +.nav-justified > .nav-link, +.nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} + +.nav-fill .nav-item .nav-link, +.nav-justified .nav-item .nav-link { + width: 100%; +} + +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} + +.navbar { + --bs-navbar-padding-x: 0; + --bs-navbar-padding-y: 0.5rem; + --bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65); + --bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8); + --bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3); + --bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1); + --bs-navbar-brand-padding-y: 0.3125rem; + --bs-navbar-brand-margin-end: 1rem; + --bs-navbar-brand-font-size: 1.25rem; + --bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1); + --bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1); + --bs-navbar-nav-link-padding-x: 0.5rem; + --bs-navbar-toggler-padding-y: 0.25rem; + --bs-navbar-toggler-padding-x: 0.75rem; + --bs-navbar-toggler-font-size: 1.25rem; + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); + --bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15); + --bs-navbar-toggler-border-radius: var(--bs-border-radius); + --bs-navbar-toggler-focus-width: 0.25rem; + --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out; + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x); +} +.navbar > .container, +.navbar > .container-fluid, +.navbar > .container-sm, +.navbar > .container-md, +.navbar > .container-lg, +.navbar > .container-xl, +.navbar > .container-xxl { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; +} +.navbar-brand { + padding-top: var(--bs-navbar-brand-padding-y); + padding-bottom: var(--bs-navbar-brand-padding-y); + margin-right: var(--bs-navbar-brand-margin-end); + font-size: var(--bs-navbar-brand-font-size); + color: var(--bs-navbar-brand-color); + text-decoration: none; + white-space: nowrap; +} +.navbar-brand:hover, .navbar-brand:focus { + color: var(--bs-navbar-brand-hover-color); +} + +.navbar-nav { + --bs-nav-link-padding-x: 0; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-navbar-color); + --bs-nav-link-hover-color: var(--bs-navbar-hover-color); + --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color); + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.navbar-nav .nav-link.active, .navbar-nav .nav-link.show { + color: var(--bs-navbar-active-color); +} +.navbar-nav .dropdown-menu { + position: static; +} + +.navbar-text { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-navbar-color); +} +.navbar-text a, +.navbar-text a:hover, +.navbar-text a:focus { + color: var(--bs-navbar-active-color); +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; +} + +.navbar-toggler { + padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x); + font-size: var(--bs-navbar-toggler-font-size); + line-height: 1; + color: var(--bs-navbar-color); + background-color: transparent; + border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color); + border-radius: var(--bs-navbar-toggler-border-radius); + transition: var(--bs-navbar-toggler-transition); +} +@media (prefers-reduced-motion: reduce) { + .navbar-toggler { + transition: none; + } +} +.navbar-toggler:hover { + text-decoration: none; +} +.navbar-toggler:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width); +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-image: var(--bs-navbar-toggler-icon-bg); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height, 75vh); + overflow-y: auto; +} + +@media (min-width: 576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } + .navbar-expand-sm .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-sm .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-md .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } + .navbar-expand-md .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-md .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } + .navbar-expand-lg .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-lg .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } + .navbar-expand-xl .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 1400px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xxl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xxl .navbar-toggler { + display: none; + } + .navbar-expand-xxl .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +.navbar-expand { + flex-wrap: nowrap; + justify-content: flex-start; +} +.navbar-expand .navbar-nav { + flex-direction: row; +} +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} +.navbar-expand .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); +} +.navbar-expand .navbar-nav-scroll { + overflow: visible; +} +.navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto; +} +.navbar-expand .navbar-toggler { + display: none; +} +.navbar-expand .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; +} +.navbar-expand .offcanvas .offcanvas-header { + display: none; +} +.navbar-expand .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} + +.navbar-dark, +.navbar[data-bs-theme=dark] { + --bs-navbar-color: rgba(255, 255, 255, 0.55); + --bs-navbar-hover-color: rgba(255, 255, 255, 0.75); + --bs-navbar-disabled-color: rgba(255, 255, 255, 0.25); + --bs-navbar-active-color: #fff; + --bs-navbar-brand-color: #fff; + --bs-navbar-brand-hover-color: #fff; + --bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1); + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +[data-bs-theme=dark] .navbar-toggler-icon { + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.card { + --bs-card-spacer-y: 1rem; + --bs-card-spacer-x: 1rem; + --bs-card-title-spacer-y: 0.5rem; + --bs-card-title-color: ; + --bs-card-subtitle-color: ; + --bs-card-border-width: var(--bs-border-width); + --bs-card-border-color: var(--bs-border-color-translucent); + --bs-card-border-radius: var(--bs-border-radius); + --bs-card-box-shadow: ; + --bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width))); + --bs-card-cap-padding-y: 0.5rem; + --bs-card-cap-padding-x: 1rem; + --bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03); + --bs-card-cap-color: ; + --bs-card-height: ; + --bs-card-color: ; + --bs-card-bg: var(--bs-body-bg); + --bs-card-img-overlay-padding: 1rem; + --bs-card-group-margin: 0.75rem; + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + height: var(--bs-card-height); + color: var(--bs-body-color); + word-wrap: break-word; + background-color: var(--bs-card-bg); + background-clip: border-box; + border: var(--bs-card-border-width) solid var(--bs-card-border-color); + border-radius: var(--bs-card-border-radius); +} +.card > hr { + margin-right: 0; + margin-left: 0; +} +.card > .list-group { + border-top: inherit; + border-bottom: inherit; +} +.card > .list-group:first-child { + border-top-width: 0; + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} +.card > .list-group:last-child { + border-bottom-width: 0; + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} +.card > .card-header + .list-group, +.card > .list-group + .card-footer { + border-top: 0; +} + +.card-body { + flex: 1 1 auto; + padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x); + color: var(--bs-card-color); +} + +.card-title { + margin-bottom: var(--bs-card-title-spacer-y); + color: var(--bs-card-title-color); +} + +.card-subtitle { + margin-top: calc(-0.5 * var(--bs-card-title-spacer-y)); + margin-bottom: 0; + color: var(--bs-card-subtitle-color); +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link + .card-link { + margin-left: var(--bs-card-spacer-x); +} + +.card-header { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + margin-bottom: 0; + color: var(--bs-card-cap-color); + background-color: var(--bs-card-cap-bg); + border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color); +} +.card-header:first-child { + border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0; +} + +.card-footer { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + color: var(--bs-card-cap-color); + background-color: var(--bs-card-cap-bg); + border-top: var(--bs-card-border-width) solid var(--bs-card-border-color); +} +.card-footer:last-child { + border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius); +} + +.card-header-tabs { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-bottom: calc(-1 * var(--bs-card-cap-padding-y)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); + border-bottom: 0; +} +.card-header-tabs .nav-link.active { + background-color: var(--bs-card-bg); + border-bottom-color: var(--bs-card-bg); +} + +.card-header-pills { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--bs-card-img-overlay-padding); + border-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} + +.card-group > .card { + margin-bottom: var(--bs-card-group-margin); +} +@media (min-width: 576px) { + .card-group { + display: flex; + flex-flow: row wrap; + } + .card-group > .card { + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.accordion { + --bs-accordion-color: var(--bs-body-color); + --bs-accordion-bg: var(--bs-body-bg); + --bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; + --bs-accordion-border-color: var(--bs-border-color); + --bs-accordion-border-width: var(--bs-border-width); + --bs-accordion-border-radius: var(--bs-border-radius); + --bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width))); + --bs-accordion-btn-padding-x: 1.25rem; + --bs-accordion-btn-padding-y: 1rem; + --bs-accordion-btn-color: var(--bs-body-color); + --bs-accordion-btn-bg: var(--bs-accordion-bg); + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e"); + --bs-accordion-btn-icon-width: 1.25rem; + --bs-accordion-btn-icon-transform: rotate(-180deg); + --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e"); + --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + --bs-accordion-body-padding-x: 1.25rem; + --bs-accordion-body-padding-y: 1rem; + --bs-accordion-active-color: var(--bs-primary-text-emphasis); + --bs-accordion-active-bg: var(--bs-primary-bg-subtle); +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x); + font-size: 1rem; + color: var(--bs-accordion-btn-color); + text-align: left; + background-color: var(--bs-accordion-btn-bg); + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: var(--bs-accordion-transition); +} +@media (prefers-reduced-motion: reduce) { + .accordion-button { + transition: none; + } +} +.accordion-button:not(.collapsed) { + color: var(--bs-accordion-active-color); + background-color: var(--bs-accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color); +} +.accordion-button:not(.collapsed)::after { + background-image: var(--bs-accordion-btn-active-icon); + transform: var(--bs-accordion-btn-icon-transform); +} +.accordion-button::after { + flex-shrink: 0; + width: var(--bs-accordion-btn-icon-width); + height: var(--bs-accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--bs-accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--bs-accordion-btn-icon-width); + transition: var(--bs-accordion-btn-icon-transition); +} +@media (prefers-reduced-motion: reduce) { + .accordion-button::after { + transition: none; + } +} +.accordion-button:hover { + z-index: 2; +} +.accordion-button:focus { + z-index: 3; + outline: 0; + box-shadow: var(--bs-accordion-btn-focus-box-shadow); +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--bs-accordion-color); + background-color: var(--bs-accordion-bg); + border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color); +} +.accordion-item:first-of-type { + border-top-left-radius: var(--bs-accordion-border-radius); + border-top-right-radius: var(--bs-accordion-border-radius); +} +.accordion-item:first-of-type > .accordion-header .accordion-button { + border-top-left-radius: var(--bs-accordion-inner-border-radius); + border-top-right-radius: var(--bs-accordion-inner-border-radius); +} +.accordion-item:not(:first-of-type) { + border-top: 0; +} +.accordion-item:last-of-type { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} +.accordion-item:last-of-type > .accordion-header .accordion-button.collapsed { + border-bottom-right-radius: var(--bs-accordion-inner-border-radius); + border-bottom-left-radius: var(--bs-accordion-inner-border-radius); +} +.accordion-item:last-of-type > .accordion-collapse { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} + +.accordion-body { + padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x); +} + +.accordion-flush > .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} +.accordion-flush > .accordion-item:first-child { + border-top: 0; +} +.accordion-flush > .accordion-item:last-child { + border-bottom: 0; +} +.accordion-flush > .accordion-item > .accordion-header .accordion-button, .accordion-flush > .accordion-item > .accordion-header .accordion-button.collapsed { + border-radius: 0; +} +.accordion-flush > .accordion-item > .accordion-collapse { + border-radius: 0; +} + +[data-bs-theme=dark] .accordion-button::after { + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); +} + +.breadcrumb { + --bs-breadcrumb-padding-x: 0; + --bs-breadcrumb-padding-y: 0; + --bs-breadcrumb-margin-bottom: 1rem; + --bs-breadcrumb-bg: ; + --bs-breadcrumb-border-radius: ; + --bs-breadcrumb-divider-color: var(--bs-secondary-color); + --bs-breadcrumb-item-padding-x: 0.5rem; + --bs-breadcrumb-item-active-color: var(--bs-secondary-color); + display: flex; + flex-wrap: wrap; + padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x); + margin-bottom: var(--bs-breadcrumb-margin-bottom); + font-size: var(--bs-breadcrumb-font-size); + list-style: none; + background-color: var(--bs-breadcrumb-bg); + border-radius: var(--bs-breadcrumb-border-radius); +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: var(--bs-breadcrumb-item-padding-x); +} +.breadcrumb-item + .breadcrumb-item::before { + float: left; + padding-right: var(--bs-breadcrumb-item-padding-x); + color: var(--bs-breadcrumb-divider-color); + content: var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */; +} +.breadcrumb-item.active { + color: var(--bs-breadcrumb-item-active-color); +} + +.pagination { + --bs-pagination-padding-x: 0.75rem; + --bs-pagination-padding-y: 0.375rem; + --bs-pagination-font-size: 1rem; + --bs-pagination-color: var(--bs-link-color); + --bs-pagination-bg: var(--bs-body-bg); + --bs-pagination-border-width: var(--bs-border-width); + --bs-pagination-border-color: var(--bs-border-color); + --bs-pagination-border-radius: var(--bs-border-radius); + --bs-pagination-hover-color: var(--bs-link-hover-color); + --bs-pagination-hover-bg: var(--bs-tertiary-bg); + --bs-pagination-hover-border-color: var(--bs-border-color); + --bs-pagination-focus-color: var(--bs-link-hover-color); + --bs-pagination-focus-bg: var(--bs-secondary-bg); + --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + --bs-pagination-active-color: #fff; + --bs-pagination-active-bg: #0d6efd; + --bs-pagination-active-border-color: #0d6efd; + --bs-pagination-disabled-color: var(--bs-secondary-color); + --bs-pagination-disabled-bg: var(--bs-secondary-bg); + --bs-pagination-disabled-border-color: var(--bs-border-color); + display: flex; + padding-left: 0; + list-style: none; +} + +.page-link { + position: relative; + display: block; + padding: var(--bs-pagination-padding-y) var(--bs-pagination-padding-x); + font-size: var(--bs-pagination-font-size); + color: var(--bs-pagination-color); + text-decoration: none; + background-color: var(--bs-pagination-bg); + border: var(--bs-pagination-border-width) solid var(--bs-pagination-border-color); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .page-link { + transition: none; + } +} +.page-link:hover { + z-index: 2; + color: var(--bs-pagination-hover-color); + background-color: var(--bs-pagination-hover-bg); + border-color: var(--bs-pagination-hover-border-color); +} +.page-link:focus { + z-index: 3; + color: var(--bs-pagination-focus-color); + background-color: var(--bs-pagination-focus-bg); + outline: 0; + box-shadow: var(--bs-pagination-focus-box-shadow); +} +.page-link.active, .active > .page-link { + z-index: 3; + color: var(--bs-pagination-active-color); + background-color: var(--bs-pagination-active-bg); + border-color: var(--bs-pagination-active-border-color); +} +.page-link.disabled, .disabled > .page-link { + color: var(--bs-pagination-disabled-color); + pointer-events: none; + background-color: var(--bs-pagination-disabled-bg); + border-color: var(--bs-pagination-disabled-border-color); +} + +.page-item:not(:first-child) .page-link { + margin-left: calc(var(--bs-border-width) * -1); +} +.page-item:first-child .page-link { + border-top-left-radius: var(--bs-pagination-border-radius); + border-bottom-left-radius: var(--bs-pagination-border-radius); +} +.page-item:last-child .page-link { + border-top-right-radius: var(--bs-pagination-border-radius); + border-bottom-right-radius: var(--bs-pagination-border-radius); +} + +.pagination-lg { + --bs-pagination-padding-x: 1.5rem; + --bs-pagination-padding-y: 0.75rem; + --bs-pagination-font-size: 1.25rem; + --bs-pagination-border-radius: var(--bs-border-radius-lg); +} + +.pagination-sm { + --bs-pagination-padding-x: 0.5rem; + --bs-pagination-padding-y: 0.25rem; + --bs-pagination-font-size: 0.875rem; + --bs-pagination-border-radius: var(--bs-border-radius-sm); +} + +.badge { + --bs-badge-padding-x: 0.65em; + --bs-badge-padding-y: 0.35em; + --bs-badge-font-size: 0.75em; + --bs-badge-font-weight: 700; + --bs-badge-color: #fff; + --bs-badge-border-radius: var(--bs-border-radius); + display: inline-block; + padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x); + font-size: var(--bs-badge-font-size); + font-weight: var(--bs-badge-font-weight); + line-height: 1; + color: var(--bs-badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: var(--bs-badge-border-radius); +} +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.alert { + --bs-alert-bg: transparent; + --bs-alert-padding-x: 1rem; + --bs-alert-padding-y: 1rem; + --bs-alert-margin-bottom: 1rem; + --bs-alert-color: inherit; + --bs-alert-border-color: transparent; + --bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color); + --bs-alert-border-radius: var(--bs-border-radius); + --bs-alert-link-color: inherit; + position: relative; + padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x); + margin-bottom: var(--bs-alert-margin-bottom); + color: var(--bs-alert-color); + background-color: var(--bs-alert-bg); + border: var(--bs-alert-border); + border-radius: var(--bs-alert-border-radius); +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 700; + color: var(--bs-alert-link-color); +} + +.alert-dismissible { + padding-right: 3rem; +} +.alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.25rem 1rem; +} + +.alert-primary { + --bs-alert-color: var(--bs-primary-text-emphasis); + --bs-alert-bg: var(--bs-primary-bg-subtle); + --bs-alert-border-color: var(--bs-primary-border-subtle); + --bs-alert-link-color: var(--bs-primary-text-emphasis); +} + +.alert-secondary { + --bs-alert-color: var(--bs-secondary-text-emphasis); + --bs-alert-bg: var(--bs-secondary-bg-subtle); + --bs-alert-border-color: var(--bs-secondary-border-subtle); + --bs-alert-link-color: var(--bs-secondary-text-emphasis); +} + +.alert-success { + --bs-alert-color: var(--bs-success-text-emphasis); + --bs-alert-bg: var(--bs-success-bg-subtle); + --bs-alert-border-color: var(--bs-success-border-subtle); + --bs-alert-link-color: var(--bs-success-text-emphasis); +} + +.alert-info { + --bs-alert-color: var(--bs-info-text-emphasis); + --bs-alert-bg: var(--bs-info-bg-subtle); + --bs-alert-border-color: var(--bs-info-border-subtle); + --bs-alert-link-color: var(--bs-info-text-emphasis); +} + +.alert-warning { + --bs-alert-color: var(--bs-warning-text-emphasis); + --bs-alert-bg: var(--bs-warning-bg-subtle); + --bs-alert-border-color: var(--bs-warning-border-subtle); + --bs-alert-link-color: var(--bs-warning-text-emphasis); +} + +.alert-danger { + --bs-alert-color: var(--bs-danger-text-emphasis); + --bs-alert-bg: var(--bs-danger-bg-subtle); + --bs-alert-border-color: var(--bs-danger-border-subtle); + --bs-alert-link-color: var(--bs-danger-text-emphasis); +} + +.alert-light { + --bs-alert-color: var(--bs-light-text-emphasis); + --bs-alert-bg: var(--bs-light-bg-subtle); + --bs-alert-border-color: var(--bs-light-border-subtle); + --bs-alert-link-color: var(--bs-light-text-emphasis); +} + +.alert-dark { + --bs-alert-color: var(--bs-dark-text-emphasis); + --bs-alert-bg: var(--bs-dark-bg-subtle); + --bs-alert-border-color: var(--bs-dark-border-subtle); + --bs-alert-link-color: var(--bs-dark-text-emphasis); +} + +@keyframes progress-bar-stripes { + 0% { + background-position-x: 1rem; + } +} +.progress, +.progress-stacked { + --bs-progress-height: 1rem; + --bs-progress-font-size: 0.75rem; + --bs-progress-bg: var(--bs-secondary-bg); + --bs-progress-border-radius: var(--bs-border-radius); + --bs-progress-box-shadow: var(--bs-box-shadow-inset); + --bs-progress-bar-color: #fff; + --bs-progress-bar-bg: #0d6efd; + --bs-progress-bar-transition: width 0.6s ease; + display: flex; + height: var(--bs-progress-height); + overflow: hidden; + font-size: var(--bs-progress-font-size); + background-color: var(--bs-progress-bg); + border-radius: var(--bs-progress-border-radius); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--bs-progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--bs-progress-bar-bg); + transition: var(--bs-progress-bar-transition); +} +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: var(--bs-progress-height) var(--bs-progress-height); +} + +.progress-stacked > .progress { + overflow: visible; +} + +.progress-stacked > .progress > .progress-bar { + width: 100%; +} + +.progress-bar-animated { + animation: 1s linear infinite progress-bar-stripes; +} +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + animation: none; + } +} + +.list-group { + --bs-list-group-color: var(--bs-body-color); + --bs-list-group-bg: var(--bs-body-bg); + --bs-list-group-border-color: var(--bs-border-color); + --bs-list-group-border-width: var(--bs-border-width); + --bs-list-group-border-radius: var(--bs-border-radius); + --bs-list-group-item-padding-x: 1rem; + --bs-list-group-item-padding-y: 0.5rem; + --bs-list-group-action-color: var(--bs-secondary-color); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-tertiary-bg); + --bs-list-group-action-active-color: var(--bs-body-color); + --bs-list-group-action-active-bg: var(--bs-secondary-bg); + --bs-list-group-disabled-color: var(--bs-secondary-color); + --bs-list-group-disabled-bg: var(--bs-body-bg); + --bs-list-group-active-color: #fff; + --bs-list-group-active-bg: #0d6efd; + --bs-list-group-active-border-color: #0d6efd; + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: var(--bs-list-group-border-radius); +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; +} +.list-group-numbered > .list-group-item::before { + content: counters(section, ".") ". "; + counter-increment: section; +} + +.list-group-item-action { + width: 100%; + color: var(--bs-list-group-action-color); + text-align: inherit; +} +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: var(--bs-list-group-action-hover-color); + text-decoration: none; + background-color: var(--bs-list-group-action-hover-bg); +} +.list-group-item-action:active { + color: var(--bs-list-group-action-active-color); + background-color: var(--bs-list-group-action-active-bg); +} + +.list-group-item { + position: relative; + display: block; + padding: var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x); + color: var(--bs-list-group-color); + text-decoration: none; + background-color: var(--bs-list-group-bg); + border: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color); +} +.list-group-item:first-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} +.list-group-item:last-child { + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit; +} +.list-group-item.disabled, .list-group-item:disabled { + color: var(--bs-list-group-disabled-color); + pointer-events: none; + background-color: var(--bs-list-group-disabled-bg); +} +.list-group-item.active { + z-index: 2; + color: var(--bs-list-group-active-color); + background-color: var(--bs-list-group-active-bg); + border-color: var(--bs-list-group-active-border-color); +} +.list-group-item + .list-group-item { + border-top-width: 0; +} +.list-group-item + .list-group-item.active { + margin-top: calc(-1 * var(--bs-list-group-border-width)); + border-top-width: var(--bs-list-group-border-width); +} + +.list-group-horizontal { + flex-direction: row; +} +.list-group-horizontal > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; +} +.list-group-horizontal > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; +} +.list-group-horizontal > .list-group-item.active { + margin-top: 0; +} +.list-group-horizontal > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; +} +.list-group-horizontal > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + flex-direction: row; + } + .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-sm > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 768px) { + .list-group-horizontal-md { + flex-direction: row; + } + .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-md > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 992px) { + .list-group-horizontal-lg { + flex-direction: row; + } + .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-lg > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 1200px) { + .list-group-horizontal-xl { + flex-direction: row; + } + .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-xl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 1400px) { + .list-group-horizontal-xxl { + flex-direction: row; + } + .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +.list-group-flush { + border-radius: 0; +} +.list-group-flush > .list-group-item { + border-width: 0 0 var(--bs-list-group-border-width); +} +.list-group-flush > .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + --bs-list-group-color: var(--bs-primary-text-emphasis); + --bs-list-group-bg: var(--bs-primary-bg-subtle); + --bs-list-group-border-color: var(--bs-primary-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-primary-border-subtle); + --bs-list-group-active-color: var(--bs-primary-bg-subtle); + --bs-list-group-active-bg: var(--bs-primary-text-emphasis); + --bs-list-group-active-border-color: var(--bs-primary-text-emphasis); +} + +.list-group-item-secondary { + --bs-list-group-color: var(--bs-secondary-text-emphasis); + --bs-list-group-bg: var(--bs-secondary-bg-subtle); + --bs-list-group-border-color: var(--bs-secondary-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-secondary-border-subtle); + --bs-list-group-active-color: var(--bs-secondary-bg-subtle); + --bs-list-group-active-bg: var(--bs-secondary-text-emphasis); + --bs-list-group-active-border-color: var(--bs-secondary-text-emphasis); +} + +.list-group-item-success { + --bs-list-group-color: var(--bs-success-text-emphasis); + --bs-list-group-bg: var(--bs-success-bg-subtle); + --bs-list-group-border-color: var(--bs-success-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-success-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-success-border-subtle); + --bs-list-group-active-color: var(--bs-success-bg-subtle); + --bs-list-group-active-bg: var(--bs-success-text-emphasis); + --bs-list-group-active-border-color: var(--bs-success-text-emphasis); +} + +.list-group-item-info { + --bs-list-group-color: var(--bs-info-text-emphasis); + --bs-list-group-bg: var(--bs-info-bg-subtle); + --bs-list-group-border-color: var(--bs-info-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-info-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-info-border-subtle); + --bs-list-group-active-color: var(--bs-info-bg-subtle); + --bs-list-group-active-bg: var(--bs-info-text-emphasis); + --bs-list-group-active-border-color: var(--bs-info-text-emphasis); +} + +.list-group-item-warning { + --bs-list-group-color: var(--bs-warning-text-emphasis); + --bs-list-group-bg: var(--bs-warning-bg-subtle); + --bs-list-group-border-color: var(--bs-warning-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-warning-border-subtle); + --bs-list-group-active-color: var(--bs-warning-bg-subtle); + --bs-list-group-active-bg: var(--bs-warning-text-emphasis); + --bs-list-group-active-border-color: var(--bs-warning-text-emphasis); +} + +.list-group-item-danger { + --bs-list-group-color: var(--bs-danger-text-emphasis); + --bs-list-group-bg: var(--bs-danger-bg-subtle); + --bs-list-group-border-color: var(--bs-danger-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-danger-border-subtle); + --bs-list-group-active-color: var(--bs-danger-bg-subtle); + --bs-list-group-active-bg: var(--bs-danger-text-emphasis); + --bs-list-group-active-border-color: var(--bs-danger-text-emphasis); +} + +.list-group-item-light { + --bs-list-group-color: var(--bs-light-text-emphasis); + --bs-list-group-bg: var(--bs-light-bg-subtle); + --bs-list-group-border-color: var(--bs-light-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-light-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-light-border-subtle); + --bs-list-group-active-color: var(--bs-light-bg-subtle); + --bs-list-group-active-bg: var(--bs-light-text-emphasis); + --bs-list-group-active-border-color: var(--bs-light-text-emphasis); +} + +.list-group-item-dark { + --bs-list-group-color: var(--bs-dark-text-emphasis); + --bs-list-group-bg: var(--bs-dark-bg-subtle); + --bs-list-group-border-color: var(--bs-dark-border-subtle); + --bs-list-group-action-hover-color: var(--bs-emphasis-color); + --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle); + --bs-list-group-action-active-color: var(--bs-emphasis-color); + --bs-list-group-action-active-bg: var(--bs-dark-border-subtle); + --bs-list-group-active-color: var(--bs-dark-bg-subtle); + --bs-list-group-active-bg: var(--bs-dark-text-emphasis); + --bs-list-group-active-border-color: var(--bs-dark-text-emphasis); +} + +.btn-close { + --bs-btn-close-color: #000; + --bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e"); + --bs-btn-close-opacity: 0.5; + --bs-btn-close-hover-opacity: 0.75; + --bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + --bs-btn-close-focus-opacity: 1; + --bs-btn-close-disabled-opacity: 0.25; + --bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%); + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + color: var(--bs-btn-close-color); + background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat; + border: 0; + border-radius: 0.375rem; + opacity: var(--bs-btn-close-opacity); +} +.btn-close:hover { + color: var(--bs-btn-close-color); + text-decoration: none; + opacity: var(--bs-btn-close-hover-opacity); +} +.btn-close:focus { + outline: 0; + box-shadow: var(--bs-btn-close-focus-shadow); + opacity: var(--bs-btn-close-focus-opacity); +} +.btn-close:disabled, .btn-close.disabled { + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + opacity: var(--bs-btn-close-disabled-opacity); +} + +.btn-close-white { + filter: var(--bs-btn-close-white-filter); +} + +[data-bs-theme=dark] .btn-close { + filter: var(--bs-btn-close-white-filter); +} + +.toast { + --bs-toast-zindex: 1090; + --bs-toast-padding-x: 0.75rem; + --bs-toast-padding-y: 0.5rem; + --bs-toast-spacing: 1.5rem; + --bs-toast-max-width: 350px; + --bs-toast-font-size: 0.875rem; + --bs-toast-color: ; + --bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85); + --bs-toast-border-width: var(--bs-border-width); + --bs-toast-border-color: var(--bs-border-color-translucent); + --bs-toast-border-radius: var(--bs-border-radius); + --bs-toast-box-shadow: var(--bs-box-shadow); + --bs-toast-header-color: var(--bs-secondary-color); + --bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85); + --bs-toast-header-border-color: var(--bs-border-color-translucent); + width: var(--bs-toast-max-width); + max-width: 100%; + font-size: var(--bs-toast-font-size); + color: var(--bs-toast-color); + pointer-events: auto; + background-color: var(--bs-toast-bg); + background-clip: padding-box; + border: var(--bs-toast-border-width) solid var(--bs-toast-border-color); + box-shadow: var(--bs-toast-box-shadow); + border-radius: var(--bs-toast-border-radius); +} +.toast.showing { + opacity: 0; +} +.toast:not(.show) { + display: none; +} + +.toast-container { + --bs-toast-zindex: 1090; + position: absolute; + z-index: var(--bs-toast-zindex); + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 100%; + pointer-events: none; +} +.toast-container > :not(:last-child) { + margin-bottom: var(--bs-toast-spacing); +} + +.toast-header { + display: flex; + align-items: center; + padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); + color: var(--bs-toast-header-color); + background-color: var(--bs-toast-header-bg); + background-clip: padding-box; + border-bottom: var(--bs-toast-border-width) solid var(--bs-toast-header-border-color); + border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width)); + border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width)); +} +.toast-header .btn-close { + margin-right: calc(-0.5 * var(--bs-toast-padding-x)); + margin-left: var(--bs-toast-padding-x); +} + +.toast-body { + padding: var(--bs-toast-padding-x); + word-wrap: break-word; +} + +.modal { + --bs-modal-zindex: 1055; + --bs-modal-width: 500px; + --bs-modal-padding: 1rem; + --bs-modal-margin: 0.5rem; + --bs-modal-color: ; + --bs-modal-bg: var(--bs-body-bg); + --bs-modal-border-color: var(--bs-border-color-translucent); + --bs-modal-border-width: var(--bs-border-width); + --bs-modal-border-radius: var(--bs-border-radius-lg); + --bs-modal-box-shadow: var(--bs-box-shadow-sm); + --bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width))); + --bs-modal-header-padding-x: 1rem; + --bs-modal-header-padding-y: 1rem; + --bs-modal-header-padding: 1rem 1rem; + --bs-modal-header-border-color: var(--bs-border-color); + --bs-modal-header-border-width: var(--bs-border-width); + --bs-modal-title-line-height: 1.5; + --bs-modal-footer-gap: 0.5rem; + --bs-modal-footer-bg: ; + --bs-modal-footer-border-color: var(--bs-border-color); + --bs-modal-footer-border-width: var(--bs-border-width); + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-modal-zindex); + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: var(--bs-modal-margin); + pointer-events: none; +} +.modal.fade .modal-dialog { + transition: transform 0.3s ease-out; + transform: translate(0, -50px); +} +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} +.modal.show .modal-dialog { + transform: none; +} +.modal.modal-static .modal-dialog { + transform: scale(1.02); +} + +.modal-dialog-scrollable { + height: calc(100% - var(--bs-modal-margin) * 2); +} +.modal-dialog-scrollable .modal-content { + max-height: 100%; + overflow: hidden; +} +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - var(--bs-modal-margin) * 2); +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + color: var(--bs-modal-color); + pointer-events: auto; + background-color: var(--bs-modal-bg); + background-clip: padding-box; + border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); + border-radius: var(--bs-modal-border-radius); + outline: 0; +} + +.modal-backdrop { + --bs-backdrop-zindex: 1050; + --bs-backdrop-bg: #000; + --bs-backdrop-opacity: 0.5; + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-backdrop-zindex); + width: 100vw; + height: 100vh; + background-color: var(--bs-backdrop-bg); +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop.show { + opacity: var(--bs-backdrop-opacity); +} + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + padding: var(--bs-modal-header-padding); + border-bottom: var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color); + border-top-left-radius: var(--bs-modal-inner-border-radius); + border-top-right-radius: var(--bs-modal-inner-border-radius); +} +.modal-header .btn-close { + padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5); + margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto; +} + +.modal-title { + margin-bottom: 0; + line-height: var(--bs-modal-title-line-height); +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: var(--bs-modal-padding); +} + +.modal-footer { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5); + background-color: var(--bs-modal-footer-bg); + border-top: var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color); + border-bottom-right-radius: var(--bs-modal-inner-border-radius); + border-bottom-left-radius: var(--bs-modal-inner-border-radius); +} +.modal-footer > * { + margin: calc(var(--bs-modal-footer-gap) * 0.5); +} + +@media (min-width: 576px) { + .modal { + --bs-modal-margin: 1.75rem; + --bs-modal-box-shadow: var(--bs-box-shadow); + } + .modal-dialog { + max-width: var(--bs-modal-width); + margin-right: auto; + margin-left: auto; + } + .modal-sm { + --bs-modal-width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + --bs-modal-width: 800px; + } +} +@media (min-width: 1200px) { + .modal-xl { + --bs-modal-width: 1140px; + } +} +.modal-fullscreen { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; +} +.modal-fullscreen .modal-content { + height: 100%; + border: 0; + border-radius: 0; +} +.modal-fullscreen .modal-header, +.modal-fullscreen .modal-footer { + border-radius: 0; +} +.modal-fullscreen .modal-body { + overflow-y: auto; +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-header, + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-md-down .modal-header, + .modal-fullscreen-md-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-md-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-header, + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-header, + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 1399.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-header, + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto; + } +} +.tooltip { + --bs-tooltip-zindex: 1080; + --bs-tooltip-max-width: 200px; + --bs-tooltip-padding-x: 0.5rem; + --bs-tooltip-padding-y: 0.25rem; + --bs-tooltip-margin: ; + --bs-tooltip-font-size: 0.875rem; + --bs-tooltip-color: var(--bs-body-bg); + --bs-tooltip-bg: var(--bs-emphasis-color); + --bs-tooltip-border-radius: var(--bs-border-radius); + --bs-tooltip-opacity: 0.9; + --bs-tooltip-arrow-width: 0.8rem; + --bs-tooltip-arrow-height: 0.4rem; + z-index: var(--bs-tooltip-zindex); + display: block; + margin: var(--bs-tooltip-margin); + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-tooltip-font-size); + word-wrap: break-word; + opacity: 0; +} +.tooltip.show { + opacity: var(--bs-tooltip-opacity); +} +.tooltip .tooltip-arrow { + display: block; + width: var(--bs-tooltip-arrow-width); + height: var(--bs-tooltip-arrow-height); +} +.tooltip .tooltip-arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow { + bottom: calc(-1 * var(--bs-tooltip-arrow-height)); +} +.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before { + top: -1px; + border-width: var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-top-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow { + left: calc(-1 * var(--bs-tooltip-arrow-height)); + width: var(--bs-tooltip-arrow-height); + height: var(--bs-tooltip-arrow-width); +} +.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before { + right: -1px; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-right-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow { + top: calc(-1 * var(--bs-tooltip-arrow-height)); +} +.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before { + bottom: -1px; + border-width: 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-bottom-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow { + right: calc(-1 * var(--bs-tooltip-arrow-height)); + width: var(--bs-tooltip-arrow-height); + height: var(--bs-tooltip-arrow-width); +} +.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before { + left: -1px; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-left-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.tooltip-inner { + max-width: var(--bs-tooltip-max-width); + padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x); + color: var(--bs-tooltip-color); + text-align: center; + background-color: var(--bs-tooltip-bg); + border-radius: var(--bs-tooltip-border-radius); +} + +.popover { + --bs-popover-zindex: 1070; + --bs-popover-max-width: 276px; + --bs-popover-font-size: 0.875rem; + --bs-popover-bg: var(--bs-body-bg); + --bs-popover-border-width: var(--bs-border-width); + --bs-popover-border-color: var(--bs-border-color-translucent); + --bs-popover-border-radius: var(--bs-border-radius-lg); + --bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width)); + --bs-popover-box-shadow: var(--bs-box-shadow); + --bs-popover-header-padding-x: 1rem; + --bs-popover-header-padding-y: 0.5rem; + --bs-popover-header-font-size: 1rem; + --bs-popover-header-color: inherit; + --bs-popover-header-bg: var(--bs-secondary-bg); + --bs-popover-body-padding-x: 1rem; + --bs-popover-body-padding-y: 1rem; + --bs-popover-body-color: var(--bs-body-color); + --bs-popover-arrow-width: 1rem; + --bs-popover-arrow-height: 0.5rem; + --bs-popover-arrow-border: var(--bs-popover-border-color); + z-index: var(--bs-popover-zindex); + display: block; + max-width: var(--bs-popover-max-width); + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-popover-font-size); + word-wrap: break-word; + background-color: var(--bs-popover-bg); + background-clip: padding-box; + border: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-radius: var(--bs-popover-border-radius); +} +.popover .popover-arrow { + display: block; + width: var(--bs-popover-arrow-width); + height: var(--bs-popover-arrow-height); +} +.popover .popover-arrow::before, .popover .popover-arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; + border-width: 0; +} + +.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow { + bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); +} +.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; +} +.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before { + bottom: 0; + border-top-color: var(--bs-popover-arrow-border); +} +.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + bottom: var(--bs-popover-border-width); + border-top-color: var(--bs-popover-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow { + left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); + width: var(--bs-popover-arrow-height); + height: var(--bs-popover-arrow-width); +} +.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; +} +.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before { + left: 0; + border-right-color: var(--bs-popover-arrow-border); +} +.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + left: var(--bs-popover-border-width); + border-right-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow { + top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); +} +.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); +} +.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before { + top: 0; + border-bottom-color: var(--bs-popover-arrow-border); +} +.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + top: var(--bs-popover-border-width); + border-bottom-color: var(--bs-popover-bg); +} +.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: var(--bs-popover-arrow-width); + margin-left: calc(-0.5 * var(--bs-popover-arrow-width)); + content: ""; + border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow { + right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); + width: var(--bs-popover-arrow-height); + height: var(--bs-popover-arrow-width); +} +.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); +} +.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before { + right: 0; + border-left-color: var(--bs-popover-arrow-border); +} +.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + right: var(--bs-popover-border-width); + border-left-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.popover-header { + padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x); + margin-bottom: 0; + font-size: var(--bs-popover-header-font-size); + color: var(--bs-popover-header-color); + background-color: var(--bs-popover-header-bg); + border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-top-left-radius: var(--bs-popover-inner-border-radius); + border-top-right-radius: var(--bs-popover-inner-border-radius); +} +.popover-header:empty { + display: none; +} + +.popover-body { + padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x); + color: var(--bs-popover-body-color); +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: transform 0.6s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start), +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end), +.active.carousel-item-start { + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none; +} +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-start, +.carousel-fade .carousel-item-prev.carousel-item-end { + z-index: 1; + opacity: 1; +} +.carousel-fade .active.carousel-item-start, +.carousel-fade .active.carousel-item-end { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} +@media (prefers-reduced-motion: reduce) { + .carousel-fade .active.carousel-item-start, + .carousel-fade .active.carousel-item-end { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 15%; + padding: 0; + color: #fff; + text-align: center; + background: none; + border: 0; + opacity: 0.5; + transition: opacity 0.15s ease; +} +@media (prefers-reduced-motion: reduce) { + .carousel-control-prev, + .carousel-control-next { + transition: none; + } +} +.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 2rem; + height: 2rem; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100%; +} + +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")*/; +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")*/; +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + margin-right: 15%; + margin-bottom: 1rem; + margin-left: 15%; +} +.carousel-indicators [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: 30px; + height: 3px; + padding: 0; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: 0.5; + transition: opacity 0.6s ease; +} +@media (prefers-reduced-motion: reduce) { + .carousel-indicators [data-bs-target] { + transition: none; + } +} +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 1.25rem; + left: 15%; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + color: #fff; + text-align: center; +} + +.carousel-dark .carousel-control-prev-icon, +.carousel-dark .carousel-control-next-icon { + filter: invert(1) grayscale(100); +} +.carousel-dark .carousel-indicators [data-bs-target] { + background-color: #000; +} +.carousel-dark .carousel-caption { + color: #000; +} + +[data-bs-theme=dark] .carousel .carousel-control-prev-icon, +[data-bs-theme=dark] .carousel .carousel-control-next-icon, [data-bs-theme=dark].carousel .carousel-control-prev-icon, +[data-bs-theme=dark].carousel .carousel-control-next-icon { + filter: invert(1) grayscale(100); +} +[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target], [data-bs-theme=dark].carousel .carousel-indicators [data-bs-target] { + background-color: #000; +} +[data-bs-theme=dark] .carousel .carousel-caption, [data-bs-theme=dark].carousel .carousel-caption { + color: #000; +} + +.spinner-grow, +.spinner-border { + display: inline-block; + width: var(--bs-spinner-width); + height: var(--bs-spinner-height); + vertical-align: var(--bs-spinner-vertical-align); + border-radius: 50%; + animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name); +} + +@keyframes spinner-border { + to { + transform: rotate(360deg) /* rtl:ignore */; + } +} +.spinner-border { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-border-width: 0.25em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-border; + border: var(--bs-spinner-border-width) solid currentcolor; + border-right-color: transparent; +} + +.spinner-border-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; + --bs-spinner-border-width: 0.2em; +} + +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} +.spinner-grow { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-grow; + background-color: currentcolor; + opacity: 0; +} + +.spinner-grow-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; +} + +@media (prefers-reduced-motion: reduce) { + .spinner-border, + .spinner-grow { + --bs-spinner-animation-speed: 1.5s; + } +} +.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm { + --bs-offcanvas-zindex: 1045; + --bs-offcanvas-width: 400px; + --bs-offcanvas-height: 30vh; + --bs-offcanvas-padding-x: 1rem; + --bs-offcanvas-padding-y: 1rem; + --bs-offcanvas-color: var(--bs-body-color); + --bs-offcanvas-bg: var(--bs-body-bg); + --bs-offcanvas-border-width: var(--bs-border-width); + --bs-offcanvas-border-color: var(--bs-border-color-translucent); + --bs-offcanvas-box-shadow: var(--bs-box-shadow-sm); + --bs-offcanvas-transition: transform 0.3s ease-in-out; + --bs-offcanvas-title-line-height: 1.5; +} + +@media (max-width: 575.98px) { + .offcanvas-sm { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); + } +} +@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-sm { + transition: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-sm.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-sm.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-sm.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } + .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { + transform: none; + } + .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { + visibility: visible; + } +} +@media (min-width: 576px) { + .offcanvas-sm { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-sm .offcanvas-header { + display: none; + } + .offcanvas-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 767.98px) { + .offcanvas-md { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); + } +} +@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-md { + transition: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-md.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-md.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-md.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } + .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { + transform: none; + } + .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { + visibility: visible; + } +} +@media (min-width: 768px) { + .offcanvas-md { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-md .offcanvas-header { + display: none; + } + .offcanvas-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 991.98px) { + .offcanvas-lg { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); + } +} +@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-lg { + transition: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-lg.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-lg.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-lg.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } + .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { + transform: none; + } + .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { + visibility: visible; + } +} +@media (min-width: 992px) { + .offcanvas-lg { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-lg .offcanvas-header { + display: none; + } + .offcanvas-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1199.98px) { + .offcanvas-xl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); + } +} +@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-xl { + transition: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-xl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-xl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-xl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } + .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { + transform: none; + } + .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { + visibility: visible; + } +} +@media (min-width: 1200px) { + .offcanvas-xl { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-xl .offcanvas-header { + display: none; + } + .offcanvas-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1399.98px) { + .offcanvas-xxl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); + } +} +@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-xxl { + transition: none; + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } + .offcanvas-xxl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } + .offcanvas-xxl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } + .offcanvas-xxl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } + .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { + transform: none; + } + .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { + visibility: visible; + } +} +@media (min-width: 1400px) { + .offcanvas-xxl { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-xxl .offcanvas-header { + display: none; + } + .offcanvas-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +.offcanvas { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: var(--bs-offcanvas-transition); +} +@media (prefers-reduced-motion: reduce) { + .offcanvas { + transition: none; + } +} +.offcanvas.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); +} +.offcanvas.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); +} +.offcanvas.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); +} +.offcanvas.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); +} +.offcanvas.showing, .offcanvas.show:not(.hiding) { + transform: none; +} +.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { + visibility: visible; +} + +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} +.offcanvas-backdrop.fade { + opacity: 0; +} +.offcanvas-backdrop.show { + opacity: 0.5; +} + +.offcanvas-header { + display: flex; + align-items: center; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); +} +.offcanvas-header .btn-close { + padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5); + margin: calc(-0.5 * var(--bs-offcanvas-padding-y)) calc(-0.5 * var(--bs-offcanvas-padding-x)) calc(-0.5 * var(--bs-offcanvas-padding-y)) auto; +} + +.offcanvas-title { + margin-bottom: 0; + line-height: var(--bs-offcanvas-title-line-height); +} + +.offcanvas-body { + flex-grow: 1; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); + overflow-y: auto; +} + +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentcolor; + opacity: 0.5; +} +.placeholder.btn::before { + display: inline-block; + content: ""; +} + +.placeholder-xs { + min-height: 0.6em; +} + +.placeholder-sm { + min-height: 0.8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +.placeholder-glow .placeholder { + animation: placeholder-glow 2s ease-in-out infinite; +} + +@keyframes placeholder-glow { + 50% { + opacity: 0.2; + } +} +.placeholder-wave { + -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + -webkit-mask-size: 200% 100%; + mask-size: 200% 100%; + animation: placeholder-wave 2s linear infinite; +} + +@keyframes placeholder-wave { + 100% { + -webkit-mask-position: -200% 0%; + mask-position: -200% 0%; + } +} +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.text-bg-primary { + color: #fff !important; + background-color: RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-secondary { + color: #fff !important; + background-color: RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-success { + color: #fff !important; + background-color: RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-info { + color: #000 !important; + background-color: RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-warning { + color: #000 !important; + background-color: RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-danger { + color: #fff !important; + background-color: RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-light { + color: #000 !important; + background-color: RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-dark { + color: #fff !important; + background-color: RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important; +} + +.link-primary { + color: RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-primary:hover, .link-primary:focus { + color: RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-secondary { + color: RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-secondary:hover, .link-secondary:focus { + color: RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-success { + color: RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-success:hover, .link-success:focus { + color: RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-info { + color: RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-info:hover, .link-info:focus { + color: RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-warning { + color: RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-warning:hover, .link-warning:focus { + color: RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-danger { + color: RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-danger:hover, .link-danger:focus { + color: RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-light { + color: RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-light:hover, .link-light:focus { + color: RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-dark { + color: RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-dark:hover, .link-dark:focus { + color: RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important; +} + +.link-body-emphasis { + color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important; +} +.link-body-emphasis:hover, .link-body-emphasis:focus { + color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important; + -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important; + text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important; +} + +.focus-ring:focus { + outline: 0; + box-shadow: var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color); +} + +.icon-link { + display: inline-flex; + gap: 0.375rem; + align-items: center; + -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5)); + text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5)); + text-underline-offset: 0.25em; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; +} +.icon-link > .bi { + flex-shrink: 0; + width: 1em; + height: 1em; + fill: currentcolor; + transition: 0.2s ease-in-out transform; +} +@media (prefers-reduced-motion: reduce) { + .icon-link > .bi { + transition: none; + } +} + +.icon-link-hover:hover > .bi, .icon-link-hover:focus-visible > .bi { + transform: var(--bs-icon-link-transform, translate3d(0.25em, 0, 0)); +} + +.ratio { + position: relative; + width: 100%; +} +.ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: ""; +} +.ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ratio-1x1 { + --bs-aspect-ratio: 100%; +} + +.ratio-4x3 { + --bs-aspect-ratio: 75%; +} + +.ratio-16x9 { + --bs-aspect-ratio: 56.25%; +} + +.ratio-21x9 { + --bs-aspect-ratio: 42.8571428571%; +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +.sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; +} + +.sticky-bottom { + position: -webkit-sticky; + position: sticky; + bottom: 0; + z-index: 1020; +} + +@media (min-width: 576px) { + .sticky-sm-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-sm-bottom { + position: -webkit-sticky; + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 768px) { + .sticky-md-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-md-bottom { + position: -webkit-sticky; + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 992px) { + .sticky-lg-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-lg-bottom { + position: -webkit-sticky; + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 1200px) { + .sticky-xl-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-xl-bottom { + position: -webkit-sticky; + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 1400px) { + .sticky-xxl-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-xxl-bottom { + position: -webkit-sticky; + position: sticky; + bottom: 0; + z-index: 1020; + } +} +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} +.visually-hidden:not(caption), +.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) { + position: absolute !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: ""; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vr { + display: inline-block; + align-self: stretch; + width: var(--bs-border-width); + min-height: 1em; + background-color: currentcolor; + opacity: 0.25; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.float-start { + float: left !important; +} + +.float-end { + float: right !important; +} + +.float-none { + float: none !important; +} + +.object-fit-contain { + -o-object-fit: contain !important; + object-fit: contain !important; +} + +.object-fit-cover { + -o-object-fit: cover !important; + object-fit: cover !important; +} + +.object-fit-fill { + -o-object-fit: fill !important; + object-fit: fill !important; +} + +.object-fit-scale { + -o-object-fit: scale-down !important; + object-fit: scale-down !important; +} + +.object-fit-none { + -o-object-fit: none !important; + object-fit: none !important; +} + +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.overflow-visible { + overflow: visible !important; +} + +.overflow-scroll { + overflow: scroll !important; +} + +.overflow-x-auto { + overflow-x: auto !important; +} + +.overflow-x-hidden { + overflow-x: hidden !important; +} + +.overflow-x-visible { + overflow-x: visible !important; +} + +.overflow-x-scroll { + overflow-x: scroll !important; +} + +.overflow-y-auto { + overflow-y: auto !important; +} + +.overflow-y-hidden { + overflow-y: hidden !important; +} + +.overflow-y-visible { + overflow-y: visible !important; +} + +.overflow-y-scroll { + overflow-y: scroll !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-inline-grid { + display: inline-grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.shadow { + box-shadow: var(--bs-box-shadow) !important; +} + +.shadow-sm { + box-shadow: var(--bs-box-shadow-sm) !important; +} + +.shadow-lg { + box-shadow: var(--bs-box-shadow-lg) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.focus-ring-primary { + --bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-secondary { + --bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-success { + --bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-info { + --bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-warning { + --bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-danger { + --bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-light { + --bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity)); +} + +.focus-ring-dark { + --bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity)); +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: -webkit-sticky !important; + position: sticky !important; +} + +.top-0 { + top: 0 !important; +} + +.top-50 { + top: 50% !important; +} + +.top-100 { + top: 100% !important; +} + +.bottom-0 { + bottom: 0 !important; +} + +.bottom-50 { + bottom: 50% !important; +} + +.bottom-100 { + bottom: 100% !important; +} + +.start-0 { + left: 0 !important; +} + +.start-50 { + left: 50% !important; +} + +.start-100 { + left: 100% !important; +} + +.end-0 { + right: 0 !important; +} + +.end-50 { + right: 50% !important; +} + +.end-100 { + right: 100% !important; +} + +.translate-middle { + transform: translate(-50%, -50%) !important; +} + +.translate-middle-x { + transform: translateX(-50%) !important; +} + +.translate-middle-y { + transform: translateY(-50%) !important; +} + +.border { + border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top { + border-top: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-end { + border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-end-0 { + border-right: 0 !important; +} + +.border-bottom { + border-bottom: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-start { + border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-start-0 { + border-left: 0 !important; +} + +.border-primary { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important; +} + +.border-secondary { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important; +} + +.border-success { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important; +} + +.border-info { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important; +} + +.border-warning { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important; +} + +.border-danger { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important; +} + +.border-light { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important; +} + +.border-dark { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important; +} + +.border-black { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important; +} + +.border-white { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important; +} + +.border-primary-subtle { + border-color: var(--bs-primary-border-subtle) !important; +} + +.border-secondary-subtle { + border-color: var(--bs-secondary-border-subtle) !important; +} + +.border-success-subtle { + border-color: var(--bs-success-border-subtle) !important; +} + +.border-info-subtle { + border-color: var(--bs-info-border-subtle) !important; +} + +.border-warning-subtle { + border-color: var(--bs-warning-border-subtle) !important; +} + +.border-danger-subtle { + border-color: var(--bs-danger-border-subtle) !important; +} + +.border-light-subtle { + border-color: var(--bs-light-border-subtle) !important; +} + +.border-dark-subtle { + border-color: var(--bs-dark-border-subtle) !important; +} + +.border-1 { + border-width: 1px !important; +} + +.border-2 { + border-width: 2px !important; +} + +.border-3 { + border-width: 3px !important; +} + +.border-4 { + border-width: 4px !important; +} + +.border-5 { + border-width: 5px !important; +} + +.border-opacity-10 { + --bs-border-opacity: 0.1; +} + +.border-opacity-25 { + --bs-border-opacity: 0.25; +} + +.border-opacity-50 { + --bs-border-opacity: 0.5; +} + +.border-opacity-75 { + --bs-border-opacity: 0.75; +} + +.border-opacity-100 { + --bs-border-opacity: 1; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.vw-100 { + width: 100vw !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.vh-100 { + height: 100vh !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 3rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 3rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 3rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 3rem !important; +} + +.gap-0 { + gap: 0 !important; +} + +.gap-1 { + gap: 0.25rem !important; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + +.gap-4 { + gap: 1.5rem !important; +} + +.gap-5 { + gap: 3rem !important; +} + +.row-gap-0 { + row-gap: 0 !important; +} + +.row-gap-1 { + row-gap: 0.25rem !important; +} + +.row-gap-2 { + row-gap: 0.5rem !important; +} + +.row-gap-3 { + row-gap: 1rem !important; +} + +.row-gap-4 { + row-gap: 1.5rem !important; +} + +.row-gap-5 { + row-gap: 3rem !important; +} + +.column-gap-0 { + -moz-column-gap: 0 !important; + column-gap: 0 !important; +} + +.column-gap-1 { + -moz-column-gap: 0.25rem !important; + column-gap: 0.25rem !important; +} + +.column-gap-2 { + -moz-column-gap: 0.5rem !important; + column-gap: 0.5rem !important; +} + +.column-gap-3 { + -moz-column-gap: 1rem !important; + column-gap: 1rem !important; +} + +.column-gap-4 { + -moz-column-gap: 1.5rem !important; + column-gap: 1.5rem !important; +} + +.column-gap-5 { + -moz-column-gap: 3rem !important; + column-gap: 3rem !important; +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important; +} + +.fs-1 { + font-size: calc(1.375rem + 1.5vw) !important; +} + +.fs-2 { + font-size: calc(1.325rem + 0.9vw) !important; +} + +.fs-3 { + font-size: calc(1.3rem + 0.6vw) !important; +} + +.fs-4 { + font-size: calc(1.275rem + 0.3vw) !important; +} + +.fs-5 { + font-size: 1.25rem !important; +} + +.fs-6 { + font-size: 1rem !important; +} + +.fst-italic { + font-style: italic !important; +} + +.fst-normal { + font-style: normal !important; +} + +.fw-lighter { + font-weight: lighter !important; +} + +.fw-light { + font-weight: 300 !important; +} + +.fw-normal { + font-weight: 400 !important; +} + +.fw-medium { + font-weight: 500 !important; +} + +.fw-semibold { + font-weight: 600 !important; +} + +.fw-bold { + font-weight: 700 !important; +} + +.fw-bolder { + font-weight: bolder !important; +} + +.lh-1 { + line-height: 1 !important; +} + +.lh-sm { + line-height: 1.25 !important; +} + +.lh-base { + line-height: 1.5 !important; +} + +.lh-lg { + line-height: 2 !important; +} + +.text-start { + text-align: left !important; +} + +.text-end { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-decoration-underline { + text-decoration: underline !important; +} + +.text-decoration-line-through { + text-decoration: line-through !important; +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +/* rtl:begin:remove */ +.text-break { + word-wrap: break-word !important; + word-break: break-word !important; +} + +/* rtl:end:remove */ +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; +} + +.text-muted { + --bs-text-opacity: 1; + color: var(--bs-secondary-color) !important; +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-body-secondary { + --bs-text-opacity: 1; + color: var(--bs-secondary-color) !important; +} + +.text-body-tertiary { + --bs-text-opacity: 1; + color: var(--bs-tertiary-color) !important; +} + +.text-body-emphasis { + --bs-text-opacity: 1; + color: var(--bs-emphasis-color) !important; +} + +.text-reset { + --bs-text-opacity: 1; + color: inherit !important; +} + +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + +.text-primary-emphasis { + color: var(--bs-primary-text-emphasis) !important; +} + +.text-secondary-emphasis { + color: var(--bs-secondary-text-emphasis) !important; +} + +.text-success-emphasis { + color: var(--bs-success-text-emphasis) !important; +} + +.text-info-emphasis { + color: var(--bs-info-text-emphasis) !important; +} + +.text-warning-emphasis { + color: var(--bs-warning-text-emphasis) !important; +} + +.text-danger-emphasis { + color: var(--bs-danger-text-emphasis) !important; +} + +.text-light-emphasis { + color: var(--bs-light-text-emphasis) !important; +} + +.text-dark-emphasis { + color: var(--bs-dark-text-emphasis) !important; +} + +.link-opacity-10 { + --bs-link-opacity: 0.1; +} + +.link-opacity-10-hover:hover { + --bs-link-opacity: 0.1; +} + +.link-opacity-25 { + --bs-link-opacity: 0.25; +} + +.link-opacity-25-hover:hover { + --bs-link-opacity: 0.25; +} + +.link-opacity-50 { + --bs-link-opacity: 0.5; +} + +.link-opacity-50-hover:hover { + --bs-link-opacity: 0.5; +} + +.link-opacity-75 { + --bs-link-opacity: 0.75; +} + +.link-opacity-75-hover:hover { + --bs-link-opacity: 0.75; +} + +.link-opacity-100 { + --bs-link-opacity: 1; +} + +.link-opacity-100-hover:hover { + --bs-link-opacity: 1; +} + +.link-offset-1 { + text-underline-offset: 0.125em !important; +} + +.link-offset-1-hover:hover { + text-underline-offset: 0.125em !important; +} + +.link-offset-2 { + text-underline-offset: 0.25em !important; +} + +.link-offset-2-hover:hover { + text-underline-offset: 0.25em !important; +} + +.link-offset-3 { + text-underline-offset: 0.375em !important; +} + +.link-offset-3-hover:hover { + text-underline-offset: 0.375em !important; +} + +.link-underline-primary { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-secondary { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-success { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-info { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-warning { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-danger { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-light { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline-dark { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important; + text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important; +} + +.link-underline { + --bs-link-underline-opacity: 1; + -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important; + text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important; +} + +.link-underline-opacity-0 { + --bs-link-underline-opacity: 0; +} + +.link-underline-opacity-0-hover:hover { + --bs-link-underline-opacity: 0; +} + +.link-underline-opacity-10 { + --bs-link-underline-opacity: 0.1; +} + +.link-underline-opacity-10-hover:hover { + --bs-link-underline-opacity: 0.1; +} + +.link-underline-opacity-25 { + --bs-link-underline-opacity: 0.25; +} + +.link-underline-opacity-25-hover:hover { + --bs-link-underline-opacity: 0.25; +} + +.link-underline-opacity-50 { + --bs-link-underline-opacity: 0.5; +} + +.link-underline-opacity-50-hover:hover { + --bs-link-underline-opacity: 0.5; +} + +.link-underline-opacity-75 { + --bs-link-underline-opacity: 0.75; +} + +.link-underline-opacity-75-hover:hover { + --bs-link-underline-opacity: 0.75; +} + +.link-underline-opacity-100 { + --bs-link-underline-opacity: 1; +} + +.link-underline-opacity-100-hover:hover { + --bs-link-underline-opacity: 1; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important; +} + +.bg-body-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body-tertiary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + +.bg-primary-subtle { + background-color: var(--bs-primary-bg-subtle) !important; +} + +.bg-secondary-subtle { + background-color: var(--bs-secondary-bg-subtle) !important; +} + +.bg-success-subtle { + background-color: var(--bs-success-bg-subtle) !important; +} + +.bg-info-subtle { + background-color: var(--bs-info-bg-subtle) !important; +} + +.bg-warning-subtle { + background-color: var(--bs-warning-bg-subtle) !important; +} + +.bg-danger-subtle { + background-color: var(--bs-danger-bg-subtle) !important; +} + +.bg-light-subtle { + background-color: var(--bs-light-bg-subtle) !important; +} + +.bg-dark-subtle { + background-color: var(--bs-dark-bg-subtle) !important; +} + +.bg-gradient { + background-image: var(--bs-gradient) !important; +} + +.user-select-all { + -webkit-user-select: all !important; + -moz-user-select: all !important; + user-select: all !important; +} + +.user-select-auto { + -webkit-user-select: auto !important; + -moz-user-select: auto !important; + user-select: auto !important; +} + +.user-select-none { + -webkit-user-select: none !important; + -moz-user-select: none !important; + user-select: none !important; +} + +.pe-none { + pointer-events: none !important; +} + +.pe-auto { + pointer-events: auto !important; +} + +.rounded { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.rounded-1 { + border-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-2 { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-3 { + border-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-4 { + border-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-5 { + border-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-top { + border-top-left-radius: var(--bs-border-radius) !important; + border-top-right-radius: var(--bs-border-radius) !important; +} + +.rounded-top-0 { + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; +} + +.rounded-top-1 { + border-top-left-radius: var(--bs-border-radius-sm) !important; + border-top-right-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-top-2 { + border-top-left-radius: var(--bs-border-radius) !important; + border-top-right-radius: var(--bs-border-radius) !important; +} + +.rounded-top-3 { + border-top-left-radius: var(--bs-border-radius-lg) !important; + border-top-right-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-top-4 { + border-top-left-radius: var(--bs-border-radius-xl) !important; + border-top-right-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-top-5 { + border-top-left-radius: var(--bs-border-radius-xxl) !important; + border-top-right-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-top-circle { + border-top-left-radius: 50% !important; + border-top-right-radius: 50% !important; +} + +.rounded-top-pill { + border-top-left-radius: var(--bs-border-radius-pill) !important; + border-top-right-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-end { + border-top-right-radius: var(--bs-border-radius) !important; + border-bottom-right-radius: var(--bs-border-radius) !important; +} + +.rounded-end-0 { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +.rounded-end-1 { + border-top-right-radius: var(--bs-border-radius-sm) !important; + border-bottom-right-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-end-2 { + border-top-right-radius: var(--bs-border-radius) !important; + border-bottom-right-radius: var(--bs-border-radius) !important; +} + +.rounded-end-3 { + border-top-right-radius: var(--bs-border-radius-lg) !important; + border-bottom-right-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-end-4 { + border-top-right-radius: var(--bs-border-radius-xl) !important; + border-bottom-right-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-end-5 { + border-top-right-radius: var(--bs-border-radius-xxl) !important; + border-bottom-right-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-end-circle { + border-top-right-radius: 50% !important; + border-bottom-right-radius: 50% !important; +} + +.rounded-end-pill { + border-top-right-radius: var(--bs-border-radius-pill) !important; + border-bottom-right-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-bottom { + border-bottom-right-radius: var(--bs-border-radius) !important; + border-bottom-left-radius: var(--bs-border-radius) !important; +} + +.rounded-bottom-0 { + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 0 !important; +} + +.rounded-bottom-1 { + border-bottom-right-radius: var(--bs-border-radius-sm) !important; + border-bottom-left-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-bottom-2 { + border-bottom-right-radius: var(--bs-border-radius) !important; + border-bottom-left-radius: var(--bs-border-radius) !important; +} + +.rounded-bottom-3 { + border-bottom-right-radius: var(--bs-border-radius-lg) !important; + border-bottom-left-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-bottom-4 { + border-bottom-right-radius: var(--bs-border-radius-xl) !important; + border-bottom-left-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-bottom-5 { + border-bottom-right-radius: var(--bs-border-radius-xxl) !important; + border-bottom-left-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-bottom-circle { + border-bottom-right-radius: 50% !important; + border-bottom-left-radius: 50% !important; +} + +.rounded-bottom-pill { + border-bottom-right-radius: var(--bs-border-radius-pill) !important; + border-bottom-left-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-start { + border-bottom-left-radius: var(--bs-border-radius) !important; + border-top-left-radius: var(--bs-border-radius) !important; +} + +.rounded-start-0 { + border-bottom-left-radius: 0 !important; + border-top-left-radius: 0 !important; +} + +.rounded-start-1 { + border-bottom-left-radius: var(--bs-border-radius-sm) !important; + border-top-left-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-start-2 { + border-bottom-left-radius: var(--bs-border-radius) !important; + border-top-left-radius: var(--bs-border-radius) !important; +} + +.rounded-start-3 { + border-bottom-left-radius: var(--bs-border-radius-lg) !important; + border-top-left-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-start-4 { + border-bottom-left-radius: var(--bs-border-radius-xl) !important; + border-top-left-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-start-5 { + border-bottom-left-radius: var(--bs-border-radius-xxl) !important; + border-top-left-radius: var(--bs-border-radius-xxl) !important; +} + +.rounded-start-circle { + border-bottom-left-radius: 50% !important; + border-top-left-radius: 50% !important; +} + +.rounded-start-pill { + border-bottom-left-radius: var(--bs-border-radius-pill) !important; + border-top-left-radius: var(--bs-border-radius-pill) !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +.z-n1 { + z-index: -1 !important; +} + +.z-0 { + z-index: 0 !important; +} + +.z-1 { + z-index: 1 !important; +} + +.z-2 { + z-index: 2 !important; +} + +.z-3 { + z-index: 3 !important; +} + +@media (min-width: 576px) { + .float-sm-start { + float: left !important; + } + .float-sm-end { + float: right !important; + } + .float-sm-none { + float: none !important; + } + .object-fit-sm-contain { + -o-object-fit: contain !important; + object-fit: contain !important; + } + .object-fit-sm-cover { + -o-object-fit: cover !important; + object-fit: cover !important; + } + .object-fit-sm-fill { + -o-object-fit: fill !important; + object-fit: fill !important; + } + .object-fit-sm-scale { + -o-object-fit: scale-down !important; + object-fit: scale-down !important; + } + .object-fit-sm-none { + -o-object-fit: none !important; + object-fit: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-inline-grid { + display: inline-grid !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-sm-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-sm-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-sm-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 3rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-right: 0 !important; + } + .me-sm-1 { + margin-right: 0.25rem !important; + } + .me-sm-2 { + margin-right: 0.5rem !important; + } + .me-sm-3 { + margin-right: 1rem !important; + } + .me-sm-4 { + margin-right: 1.5rem !important; + } + .me-sm-5 { + margin-right: 3rem !important; + } + .me-sm-auto { + margin-right: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 3rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-left: 0 !important; + } + .ms-sm-1 { + margin-left: 0.25rem !important; + } + .ms-sm-2 { + margin-left: 0.5rem !important; + } + .ms-sm-3 { + margin-left: 1rem !important; + } + .ms-sm-4 { + margin-left: 1.5rem !important; + } + .ms-sm-5 { + margin-left: 3rem !important; + } + .ms-sm-auto { + margin-left: auto !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-sm-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-sm-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-sm-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 3rem !important; + } + .pe-sm-0 { + padding-right: 0 !important; + } + .pe-sm-1 { + padding-right: 0.25rem !important; + } + .pe-sm-2 { + padding-right: 0.5rem !important; + } + .pe-sm-3 { + padding-right: 1rem !important; + } + .pe-sm-4 { + padding-right: 1.5rem !important; + } + .pe-sm-5 { + padding-right: 3rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 3rem !important; + } + .ps-sm-0 { + padding-left: 0 !important; + } + .ps-sm-1 { + padding-left: 0.25rem !important; + } + .ps-sm-2 { + padding-left: 0.5rem !important; + } + .ps-sm-3 { + padding-left: 1rem !important; + } + .ps-sm-4 { + padding-left: 1.5rem !important; + } + .ps-sm-5 { + padding-left: 3rem !important; + } + .gap-sm-0 { + gap: 0 !important; + } + .gap-sm-1 { + gap: 0.25rem !important; + } + .gap-sm-2 { + gap: 0.5rem !important; + } + .gap-sm-3 { + gap: 1rem !important; + } + .gap-sm-4 { + gap: 1.5rem !important; + } + .gap-sm-5 { + gap: 3rem !important; + } + .row-gap-sm-0 { + row-gap: 0 !important; + } + .row-gap-sm-1 { + row-gap: 0.25rem !important; + } + .row-gap-sm-2 { + row-gap: 0.5rem !important; + } + .row-gap-sm-3 { + row-gap: 1rem !important; + } + .row-gap-sm-4 { + row-gap: 1.5rem !important; + } + .row-gap-sm-5 { + row-gap: 3rem !important; + } + .column-gap-sm-0 { + -moz-column-gap: 0 !important; + column-gap: 0 !important; + } + .column-gap-sm-1 { + -moz-column-gap: 0.25rem !important; + column-gap: 0.25rem !important; + } + .column-gap-sm-2 { + -moz-column-gap: 0.5rem !important; + column-gap: 0.5rem !important; + } + .column-gap-sm-3 { + -moz-column-gap: 1rem !important; + column-gap: 1rem !important; + } + .column-gap-sm-4 { + -moz-column-gap: 1.5rem !important; + column-gap: 1.5rem !important; + } + .column-gap-sm-5 { + -moz-column-gap: 3rem !important; + column-gap: 3rem !important; + } + .text-sm-start { + text-align: left !important; + } + .text-sm-end { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} +@media (min-width: 768px) { + .float-md-start { + float: left !important; + } + .float-md-end { + float: right !important; + } + .float-md-none { + float: none !important; + } + .object-fit-md-contain { + -o-object-fit: contain !important; + object-fit: contain !important; + } + .object-fit-md-cover { + -o-object-fit: cover !important; + object-fit: cover !important; + } + .object-fit-md-fill { + -o-object-fit: fill !important; + object-fit: fill !important; + } + .object-fit-md-scale { + -o-object-fit: scale-down !important; + object-fit: scale-down !important; + } + .object-fit-md-none { + -o-object-fit: none !important; + object-fit: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-inline-grid { + display: inline-grid !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-md-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-md-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-md-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 3rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-right: 0 !important; + } + .me-md-1 { + margin-right: 0.25rem !important; + } + .me-md-2 { + margin-right: 0.5rem !important; + } + .me-md-3 { + margin-right: 1rem !important; + } + .me-md-4 { + margin-right: 1.5rem !important; + } + .me-md-5 { + margin-right: 3rem !important; + } + .me-md-auto { + margin-right: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 3rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-left: 0 !important; + } + .ms-md-1 { + margin-left: 0.25rem !important; + } + .ms-md-2 { + margin-left: 0.5rem !important; + } + .ms-md-3 { + margin-left: 1rem !important; + } + .ms-md-4 { + margin-left: 1.5rem !important; + } + .ms-md-5 { + margin-left: 3rem !important; + } + .ms-md-auto { + margin-left: auto !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-md-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-md-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-md-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 3rem !important; + } + .pe-md-0 { + padding-right: 0 !important; + } + .pe-md-1 { + padding-right: 0.25rem !important; + } + .pe-md-2 { + padding-right: 0.5rem !important; + } + .pe-md-3 { + padding-right: 1rem !important; + } + .pe-md-4 { + padding-right: 1.5rem !important; + } + .pe-md-5 { + padding-right: 3rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 3rem !important; + } + .ps-md-0 { + padding-left: 0 !important; + } + .ps-md-1 { + padding-left: 0.25rem !important; + } + .ps-md-2 { + padding-left: 0.5rem !important; + } + .ps-md-3 { + padding-left: 1rem !important; + } + .ps-md-4 { + padding-left: 1.5rem !important; + } + .ps-md-5 { + padding-left: 3rem !important; + } + .gap-md-0 { + gap: 0 !important; + } + .gap-md-1 { + gap: 0.25rem !important; + } + .gap-md-2 { + gap: 0.5rem !important; + } + .gap-md-3 { + gap: 1rem !important; + } + .gap-md-4 { + gap: 1.5rem !important; + } + .gap-md-5 { + gap: 3rem !important; + } + .row-gap-md-0 { + row-gap: 0 !important; + } + .row-gap-md-1 { + row-gap: 0.25rem !important; + } + .row-gap-md-2 { + row-gap: 0.5rem !important; + } + .row-gap-md-3 { + row-gap: 1rem !important; + } + .row-gap-md-4 { + row-gap: 1.5rem !important; + } + .row-gap-md-5 { + row-gap: 3rem !important; + } + .column-gap-md-0 { + -moz-column-gap: 0 !important; + column-gap: 0 !important; + } + .column-gap-md-1 { + -moz-column-gap: 0.25rem !important; + column-gap: 0.25rem !important; + } + .column-gap-md-2 { + -moz-column-gap: 0.5rem !important; + column-gap: 0.5rem !important; + } + .column-gap-md-3 { + -moz-column-gap: 1rem !important; + column-gap: 1rem !important; + } + .column-gap-md-4 { + -moz-column-gap: 1.5rem !important; + column-gap: 1.5rem !important; + } + .column-gap-md-5 { + -moz-column-gap: 3rem !important; + column-gap: 3rem !important; + } + .text-md-start { + text-align: left !important; + } + .text-md-end { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} +@media (min-width: 992px) { + .float-lg-start { + float: left !important; + } + .float-lg-end { + float: right !important; + } + .float-lg-none { + float: none !important; + } + .object-fit-lg-contain { + -o-object-fit: contain !important; + object-fit: contain !important; + } + .object-fit-lg-cover { + -o-object-fit: cover !important; + object-fit: cover !important; + } + .object-fit-lg-fill { + -o-object-fit: fill !important; + object-fit: fill !important; + } + .object-fit-lg-scale { + -o-object-fit: scale-down !important; + object-fit: scale-down !important; + } + .object-fit-lg-none { + -o-object-fit: none !important; + object-fit: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-inline-grid { + display: inline-grid !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-lg-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-lg-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-lg-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 3rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-right: 0 !important; + } + .me-lg-1 { + margin-right: 0.25rem !important; + } + .me-lg-2 { + margin-right: 0.5rem !important; + } + .me-lg-3 { + margin-right: 1rem !important; + } + .me-lg-4 { + margin-right: 1.5rem !important; + } + .me-lg-5 { + margin-right: 3rem !important; + } + .me-lg-auto { + margin-right: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 3rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-left: 0 !important; + } + .ms-lg-1 { + margin-left: 0.25rem !important; + } + .ms-lg-2 { + margin-left: 0.5rem !important; + } + .ms-lg-3 { + margin-left: 1rem !important; + } + .ms-lg-4 { + margin-left: 1.5rem !important; + } + .ms-lg-5 { + margin-left: 3rem !important; + } + .ms-lg-auto { + margin-left: auto !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-lg-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-lg-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-lg-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 3rem !important; + } + .pe-lg-0 { + padding-right: 0 !important; + } + .pe-lg-1 { + padding-right: 0.25rem !important; + } + .pe-lg-2 { + padding-right: 0.5rem !important; + } + .pe-lg-3 { + padding-right: 1rem !important; + } + .pe-lg-4 { + padding-right: 1.5rem !important; + } + .pe-lg-5 { + padding-right: 3rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 3rem !important; + } + .ps-lg-0 { + padding-left: 0 !important; + } + .ps-lg-1 { + padding-left: 0.25rem !important; + } + .ps-lg-2 { + padding-left: 0.5rem !important; + } + .ps-lg-3 { + padding-left: 1rem !important; + } + .ps-lg-4 { + padding-left: 1.5rem !important; + } + .ps-lg-5 { + padding-left: 3rem !important; + } + .gap-lg-0 { + gap: 0 !important; + } + .gap-lg-1 { + gap: 0.25rem !important; + } + .gap-lg-2 { + gap: 0.5rem !important; + } + .gap-lg-3 { + gap: 1rem !important; + } + .gap-lg-4 { + gap: 1.5rem !important; + } + .gap-lg-5 { + gap: 3rem !important; + } + .row-gap-lg-0 { + row-gap: 0 !important; + } + .row-gap-lg-1 { + row-gap: 0.25rem !important; + } + .row-gap-lg-2 { + row-gap: 0.5rem !important; + } + .row-gap-lg-3 { + row-gap: 1rem !important; + } + .row-gap-lg-4 { + row-gap: 1.5rem !important; + } + .row-gap-lg-5 { + row-gap: 3rem !important; + } + .column-gap-lg-0 { + -moz-column-gap: 0 !important; + column-gap: 0 !important; + } + .column-gap-lg-1 { + -moz-column-gap: 0.25rem !important; + column-gap: 0.25rem !important; + } + .column-gap-lg-2 { + -moz-column-gap: 0.5rem !important; + column-gap: 0.5rem !important; + } + .column-gap-lg-3 { + -moz-column-gap: 1rem !important; + column-gap: 1rem !important; + } + .column-gap-lg-4 { + -moz-column-gap: 1.5rem !important; + column-gap: 1.5rem !important; + } + .column-gap-lg-5 { + -moz-column-gap: 3rem !important; + column-gap: 3rem !important; + } + .text-lg-start { + text-align: left !important; + } + .text-lg-end { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} +@media (min-width: 1200px) { + .float-xl-start { + float: left !important; + } + .float-xl-end { + float: right !important; + } + .float-xl-none { + float: none !important; + } + .object-fit-xl-contain { + -o-object-fit: contain !important; + object-fit: contain !important; + } + .object-fit-xl-cover { + -o-object-fit: cover !important; + object-fit: cover !important; + } + .object-fit-xl-fill { + -o-object-fit: fill !important; + object-fit: fill !important; + } + .object-fit-xl-scale { + -o-object-fit: scale-down !important; + object-fit: scale-down !important; + } + .object-fit-xl-none { + -o-object-fit: none !important; + object-fit: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-inline-grid { + display: inline-grid !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 3rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-right: 0 !important; + } + .me-xl-1 { + margin-right: 0.25rem !important; + } + .me-xl-2 { + margin-right: 0.5rem !important; + } + .me-xl-3 { + margin-right: 1rem !important; + } + .me-xl-4 { + margin-right: 1.5rem !important; + } + .me-xl-5 { + margin-right: 3rem !important; + } + .me-xl-auto { + margin-right: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 3rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-left: 0 !important; + } + .ms-xl-1 { + margin-left: 0.25rem !important; + } + .ms-xl-2 { + margin-left: 0.5rem !important; + } + .ms-xl-3 { + margin-left: 1rem !important; + } + .ms-xl-4 { + margin-left: 1.5rem !important; + } + .ms-xl-5 { + margin-left: 3rem !important; + } + .ms-xl-auto { + margin-left: auto !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 3rem !important; + } + .pe-xl-0 { + padding-right: 0 !important; + } + .pe-xl-1 { + padding-right: 0.25rem !important; + } + .pe-xl-2 { + padding-right: 0.5rem !important; + } + .pe-xl-3 { + padding-right: 1rem !important; + } + .pe-xl-4 { + padding-right: 1.5rem !important; + } + .pe-xl-5 { + padding-right: 3rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 3rem !important; + } + .ps-xl-0 { + padding-left: 0 !important; + } + .ps-xl-1 { + padding-left: 0.25rem !important; + } + .ps-xl-2 { + padding-left: 0.5rem !important; + } + .ps-xl-3 { + padding-left: 1rem !important; + } + .ps-xl-4 { + padding-left: 1.5rem !important; + } + .ps-xl-5 { + padding-left: 3rem !important; + } + .gap-xl-0 { + gap: 0 !important; + } + .gap-xl-1 { + gap: 0.25rem !important; + } + .gap-xl-2 { + gap: 0.5rem !important; + } + .gap-xl-3 { + gap: 1rem !important; + } + .gap-xl-4 { + gap: 1.5rem !important; + } + .gap-xl-5 { + gap: 3rem !important; + } + .row-gap-xl-0 { + row-gap: 0 !important; + } + .row-gap-xl-1 { + row-gap: 0.25rem !important; + } + .row-gap-xl-2 { + row-gap: 0.5rem !important; + } + .row-gap-xl-3 { + row-gap: 1rem !important; + } + .row-gap-xl-4 { + row-gap: 1.5rem !important; + } + .row-gap-xl-5 { + row-gap: 3rem !important; + } + .column-gap-xl-0 { + -moz-column-gap: 0 !important; + column-gap: 0 !important; + } + .column-gap-xl-1 { + -moz-column-gap: 0.25rem !important; + column-gap: 0.25rem !important; + } + .column-gap-xl-2 { + -moz-column-gap: 0.5rem !important; + column-gap: 0.5rem !important; + } + .column-gap-xl-3 { + -moz-column-gap: 1rem !important; + column-gap: 1rem !important; + } + .column-gap-xl-4 { + -moz-column-gap: 1.5rem !important; + column-gap: 1.5rem !important; + } + .column-gap-xl-5 { + -moz-column-gap: 3rem !important; + column-gap: 3rem !important; + } + .text-xl-start { + text-align: left !important; + } + .text-xl-end { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} +@media (min-width: 1400px) { + .float-xxl-start { + float: left !important; + } + .float-xxl-end { + float: right !important; + } + .float-xxl-none { + float: none !important; + } + .object-fit-xxl-contain { + -o-object-fit: contain !important; + object-fit: contain !important; + } + .object-fit-xxl-cover { + -o-object-fit: cover !important; + object-fit: cover !important; + } + .object-fit-xxl-fill { + -o-object-fit: fill !important; + object-fit: fill !important; + } + .object-fit-xxl-scale { + -o-object-fit: scale-down !important; + object-fit: scale-down !important; + } + .object-fit-xxl-none { + -o-object-fit: none !important; + object-fit: none !important; + } + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-inline-grid { + display: inline-grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 3rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xxl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xxl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xxl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 3rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-right: 0 !important; + } + .me-xxl-1 { + margin-right: 0.25rem !important; + } + .me-xxl-2 { + margin-right: 0.5rem !important; + } + .me-xxl-3 { + margin-right: 1rem !important; + } + .me-xxl-4 { + margin-right: 1.5rem !important; + } + .me-xxl-5 { + margin-right: 3rem !important; + } + .me-xxl-auto { + margin-right: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 3rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-left: 0 !important; + } + .ms-xxl-1 { + margin-left: 0.25rem !important; + } + .ms-xxl-2 { + margin-left: 0.5rem !important; + } + .ms-xxl-3 { + margin-left: 1rem !important; + } + .ms-xxl-4 { + margin-left: 1.5rem !important; + } + .ms-xxl-5 { + margin-left: 3rem !important; + } + .ms-xxl-auto { + margin-left: auto !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 3rem !important; + } + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xxl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xxl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xxl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 3rem !important; + } + .pe-xxl-0 { + padding-right: 0 !important; + } + .pe-xxl-1 { + padding-right: 0.25rem !important; + } + .pe-xxl-2 { + padding-right: 0.5rem !important; + } + .pe-xxl-3 { + padding-right: 1rem !important; + } + .pe-xxl-4 { + padding-right: 1.5rem !important; + } + .pe-xxl-5 { + padding-right: 3rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 3rem !important; + } + .ps-xxl-0 { + padding-left: 0 !important; + } + .ps-xxl-1 { + padding-left: 0.25rem !important; + } + .ps-xxl-2 { + padding-left: 0.5rem !important; + } + .ps-xxl-3 { + padding-left: 1rem !important; + } + .ps-xxl-4 { + padding-left: 1.5rem !important; + } + .ps-xxl-5 { + padding-left: 3rem !important; + } + .gap-xxl-0 { + gap: 0 !important; + } + .gap-xxl-1 { + gap: 0.25rem !important; + } + .gap-xxl-2 { + gap: 0.5rem !important; + } + .gap-xxl-3 { + gap: 1rem !important; + } + .gap-xxl-4 { + gap: 1.5rem !important; + } + .gap-xxl-5 { + gap: 3rem !important; + } + .row-gap-xxl-0 { + row-gap: 0 !important; + } + .row-gap-xxl-1 { + row-gap: 0.25rem !important; + } + .row-gap-xxl-2 { + row-gap: 0.5rem !important; + } + .row-gap-xxl-3 { + row-gap: 1rem !important; + } + .row-gap-xxl-4 { + row-gap: 1.5rem !important; + } + .row-gap-xxl-5 { + row-gap: 3rem !important; + } + .column-gap-xxl-0 { + -moz-column-gap: 0 !important; + column-gap: 0 !important; + } + .column-gap-xxl-1 { + -moz-column-gap: 0.25rem !important; + column-gap: 0.25rem !important; + } + .column-gap-xxl-2 { + -moz-column-gap: 0.5rem !important; + column-gap: 0.5rem !important; + } + .column-gap-xxl-3 { + -moz-column-gap: 1rem !important; + column-gap: 1rem !important; + } + .column-gap-xxl-4 { + -moz-column-gap: 1.5rem !important; + column-gap: 1.5rem !important; + } + .column-gap-xxl-5 { + -moz-column-gap: 3rem !important; + column-gap: 3rem !important; + } + .text-xxl-start { + text-align: left !important; + } + .text-xxl-end { + text-align: right !important; + } + .text-xxl-center { + text-align: center !important; + } +} +@media (min-width: 1200px) { + .fs-1 { + font-size: 2.5rem !important; + } + .fs-2 { + font-size: 2rem !important; + } + .fs-3 { + font-size: 1.75rem !important; + } + .fs-4 { + font-size: 1.5rem !important; + } +} +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-inline-grid { + display: inline-grid !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} + +/*# sourceMappingURL=bootstrap.css.map */ \ No newline at end of file diff --git a/public/styles/bootstrap.css.map b/public/styles/bootstrap.css.map new file mode 100644 index 00000000..a1f9a189 --- /dev/null +++ b/public/styles/bootstrap.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap.css","../../scss/mixins/_banner.scss","../../scss/_root.scss","../../scss/vendor/_rfs.scss","../../scss/mixins/_color-mode.scss","../../scss/_reboot.scss","../../scss/_variables.scss","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_color-bg.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_focus-ring.scss","../../scss/helpers/_icon-link.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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EExnBlB,gBFwmB0B;AN9C9B;AG3dI;EKpGF;ILuQM,iBAAA;EH4TN;AACF;;AQpkBE;ELgQM,iCAAA;EK5PJ,gBFynBkB;EExnBlB,gBFwmB0B;ANnC9B;AGteI;EKpGF;ILuQM,eAAA;EHuUN;AACF;;AQ/kBE;ELgQM,iCAAA;EK5PJ,gBFynBkB;EExnBlB,gBFwmB0B;ANxB9B;AGjfI;EKpGF;ILuQM,iBAAA;EHkVN;AACF;;AQ1lBE;ELgQM,iCAAA;EK5PJ,gBFynBkB;EExnBlB,gBFwmB0B;ANb9B;AG5fI;EKpGF;ILuQM,eAAA;EH6VN;AACF;;AQrmBE;ELgQM,iCAAA;EK5PJ,gBFynBkB;EExnBlB,gBFwmB0B;ANF9B;AGvgBI;EKpGF;ILuQM,iBAAA;EHwWN;AACF;;AQxlBA;ECvDE,eAAA;EACA,gBAAA;ATmpBF;;AQxlBA;EC5DE,eAAA;EACA,gBAAA;ATwpBF;;AQ1lBA;EACE,qBAAA;AR6lBF;AQ3lBE;EACE,oBFsoB0B;ANzC9B;;AQnlBA;EL8MM,kBALI;EKvMR,yBAAA;ARslBF;;AQllBA;EACE,mBFiUO;EH1HH,kBALI;AHoZV;AQnlBE;EACE,gBAAA;ARqlBJ;;AQjlBA;EACE,iBAAA;EACA,mBFuTO;EH1HH,kBALI;EKtLR,cFtFS;AN0qBX;AQllBE;EACE,aAAA;ARolBJ;;AUprBA;ECIE,eAAA;EAGA,YAAA;AXkrBF;;AUnrBA;EACE,gBJ+jDkC;EI9jDlC,mCJ+jDkC;EI9jDlC,2DAAA;EHGE,sCAAA;EIRF,eAAA;EAGA,YAAA;AX2rBF;;AU7qBA;EAEE,qBAAA;AV+qBF;;AU5qBA;EACE,qBAAA;EACA,cAAA;AV+qBF;;AU5qBA;EPyPM,kBALI;EOlPR,gCJkjDkC;ANn4BpC;;AYjtBE;;;;;;;ECHA,qBAAA;EACA,gBAAA;EACA,WAAA;EACA,6CAAA;EACA,4CAAA;EACA,kBAAA;EACA,iBAAA;Ab8tBF;;AcxqBI;EF5CE;IACE,gBNkee;ENsPrB;AACF;Ac9qBI;EF5CE;IACE,gBNkee;EN2PrB;AACF;AcnrBI;EF5CE;IACE,gBNkee;ENgQrB;AACF;AcxrBI;EF5CE;IACE,iBNkee;ENqQrB;AACF;Ac7rBI;EF5CE;IACE,iBNkee;EN0QrB;AACF;Ae7vBA;EAEI,qBAAA;EAAA,yBAAA;EAAA,yBAAA;EAAA,yBAAA;EAAA,0BAAA;EAAA,2BAAA;AfmwBJ;;Ae9vBE;ECNA,qBAAA;EACA,gBAAA;EACA,aAAA;EACA,eAAA;EAEA,yCAAA;EACA,6CAAA;EACA,4CAAA;AhBuwBF;AerwBI;ECOF,cAAA;EACA,WAAA;EACA,eAAA;EACA,6CAAA;EACA,4CAAA;EACA,8BAAA;AhBiwBF;;AgBltBM;EACE,YAAA;AhBqtBR;;AgBltBM;EApCJ,cAAA;EACA,WAAA;AhB0vBF;;AgB5uBE;EACE,cAAA;EACA,WAAA;AhB+uBJ;;AgBjvBE;EACE,cAAA;EACA,UAAA;AhBovBJ;;AgBtvBE;EACE,cAAA;EACA,mBAAA;AhByvBJ;;AgB3vBE;EACE,cAAA;EACA,UAAA;AhB8vBJ;;AgBhwBE;EACE,cAAA;EACA,UAAA;AhBmwBJ;;AgBrwBE;EACE,cAAA;EACA,mBAAA;AhBwwBJ;;AgBzuBM;EAhDJ,cAAA;EACA,WAAA;AhB6xBF;;AgBxuBU;EAhEN,cAAA;EACA,kBAAA;AhB4yBJ;;AgB7uBU;EAhEN,cAAA;EACA,mBAAA;AhBizBJ;;AgBlvBU;EAhEN,cAAA;EACA,UAAA;AhBszBJ;;AgBvvBU;EAhEN,cAAA;EACA,mBAAA;AhB2zBJ;;AgB5vBU;EAhEN,cAAA;EACA,mBAAA;AhBg0BJ;;AgBjwBU;EAhEN,cAAA;EACA,UAAA;AhBq0BJ;;AgBtwBU;EAhEN,cAAA;EACA,mBAAA;AhB00BJ;;AgB3wBU;EAhEN,cAAA;EACA,mBAAA;AhB+0BJ;;AgBhxBU;EAhEN,cAAA;EACA,UAAA;AhBo1BJ;;AgBrxBU;EAhEN,cAAA;EACA,mBAAA;AhBy1BJ;;AgB1xBU;EAhEN,cAAA;EACA,mBAAA;AhB81BJ;;AgB/xBU;EAhEN,cAAA;EACA,WAAA;AhBm2BJ;;AgB5xBY;EAxDV,wBAAA;AhBw1BF;;AgBhyBY;EAxDV,yBAAA;AhB41BF;;AgBpyBY;EAxDV,gBAAA;AhBg2BF;;AgBxyBY;EAxDV,yBAAA;AhBo2BF;;AgB5yBY;EAxDV,yBAAA;AhBw2BF;;AgBhzBY;EAxDV,gBAAA;AhB42BF;;AgBpzBY;EAxDV,yBAAA;AhBg3BF;;AgBxzBY;EAxDV,yBAAA;AhBo3BF;;AgB5zBY;EAxDV,gBAAA;AhBw3BF;;AgBh0BY;EAxDV,yBAAA;AhB43BF;;AgBp0BY;EAxDV,yBAAA;AhBg4BF;;AgB7zBQ;;EAEE,gBAAA;AhBg0BV;;AgB7zBQ;;EAEE,gBAAA;AhBg0BV;;AgBv0BQ;;EAEE,sBAAA;AhB00BV;;AgBv0BQ;;EAEE,sBAAA;AhB00BV;;AgBj1BQ;;EAEE,qBAAA;AhBo1BV;;AgBj1BQ;;EAEE,qBAAA;AhBo1BV;;AgB31BQ;;EAEE,mBAAA;AhB81BV;;AgB31BQ;;EAEE,mBAAA;AhB81BV;;AgBr2BQ;;EAEE,qBAAA;AhBw2BV;;AgBr2BQ;;EAEE,qBAAA;AhBw2BV;;AgB/2BQ;;EAEE,mBAAA;AhBk3BV;;AgB/2BQ;;EAEE,mBAAA;AhBk3BV;;Ac56BI;EEUE;IACE,YAAA;EhBs6BN;EgBn6BI;IApCJ,cAAA;IACA,WAAA;EhB08BA;EgB57BA;IACE,cAAA;IACA,WAAA;EhB87BF;EgBh8BA;IACE,cAAA;IACA,UAAA;EhBk8BF;EgBp8BA;IACE,cAAA;IACA,mBAAA;EhBs8BF;EgBx8BA;IACE,cAAA;IACA,UAAA;EhB08BF;EgB58BA;IACE,cAAA;IACA,UAAA;EhB88BF;EgBh9BA;IACE,cAAA;IACA,mBAAA;EhBk9BF;EgBn7BI;IAhDJ,cAAA;IACA,WAAA;EhBs+BA;EgBj7BQ;IAhEN,cAAA;IACA,kBAAA;EhBo/BF;EgBr7BQ;IAhEN,cAAA;IACA,mBAAA;EhBw/BF;EgBz7BQ;IAhEN,cAAA;IACA,UAAA;EhB4/BF;EgB77BQ;IAhEN,cAAA;IACA,mBAAA;EhBggCF;EgBj8BQ;IAhEN,cAAA;IACA,mBAAA;EhBogCF;EgBr8BQ;IAhEN,cAAA;IACA,UAAA;EhBwgCF;EgBz8BQ;IAhEN,cAAA;IACA,mBAAA;EhB4gCF;EgB78BQ;IAhEN,cAAA;IACA,mBAAA;EhBghCF;EgBj9BQ;IAhEN,cAAA;IACA,UAAA;EhBohCF;EgBr9BQ;IAhEN,cAAA;IACA,mBAAA;EhBwhCF;EgBz9BQ;IAhEN,cAAA;IACA,mBAAA;EhB4hCF;EgB79BQ;IAhEN,cAAA;IACA,WAAA;EhBgiCF;EgBz9BU;IAxDV,cAAA;EhBohCA;EgB59BU;IAxDV,wBAAA;EhBuhCA;EgB/9BU;IAxDV,yBAAA;EhB0hCA;EgBl+BU;IAxDV,gBAAA;EhB6hCA;EgBr+BU;IAxDV,yBAAA;EhBgiCA;EgBx+BU;IAxDV,yBAAA;EhBmiCA;EgB3+BU;IAxDV,gBAAA;EhBsiCA;EgB9+BU;IAxDV,yBAAA;EhByiCA;EgBj/BU;IAxDV,yBAAA;EhB4iCA;EgBp/BU;IAxDV,gBAAA;EhB+iCA;EgBv/BU;IAxDV,yBAAA;EhBkjCA;EgB1/BU;IAxDV,yBAAA;EhBqjCA;EgBl/BM;;IAEE,gBAAA;EhBo/BR;EgBj/BM;;IAEE,gBAAA;EhBm/BR;EgB1/BM;;IAEE,sBAAA;EhB4/BR;EgBz/BM;;IAEE,sBAAA;EhB2/BR;EgBlgCM;;IAEE,qBAAA;EhBogCR;EgBjgCM;;IAEE,qBAAA;EhBmgCR;EgB1gCM;;IAEE,mBAAA;EhB4gCR;EgBzgCM;;IAEE,mBAAA;EhB2gCR;EgBlhCM;;IAEE,qBAAA;EhBohCR;EgBjhCM;;IAEE,qBAAA;EhBmhCR;EgB1hCM;;IAEE,mBAAA;EhB4hCR;EgBzhCM;;IAEE,mBAAA;EhB2hCR;AACF;ActlCI;EEUE;IACE,YAAA;EhB+kCN;EgB5kCI;IApCJ,cAAA;IACA,WAAA;EhBmnCA;EgBrmCA;IACE,cAAA;IACA,WAAA;EhBumCF;EgBzmCA;IACE,cAAA;IACA,UAAA;EhB2mCF;EgB7mCA;IACE,cAAA;IACA,mBAAA;EhB+mCF;EgBjnCA;IACE,cAAA;IACA,UAAA;EhBmnCF;EgBrnCA;IACE,cAAA;IACA,UAAA;EhBunCF;EgBznCA;IACE,cAAA;IACA,mBAAA;EhB2nCF;EgB5lCI;IAhDJ,cAAA;IACA,WAAA;EhB+oCA;EgB1lCQ;IAhEN,cAAA;IACA,kBAAA;EhB6pCF;EgB9lCQ;IAhEN,cAAA;IACA,mBAAA;EhBiqCF;EgBlmCQ;IAhEN,cAAA;IACA,UAAA;EhBqqCF;EgBtmCQ;IAhEN,cAAA;IACA,mBAAA;EhByqCF;EgB1mCQ;IAhEN,cAAA;IACA,mBAAA;EhB6qCF;EgB9mCQ;IAhEN,cAAA;IACA,UAAA;EhBirCF;EgBlnCQ;IAhEN,cAAA;IACA,mBAAA;EhBqrCF;EgBtnCQ;IAhEN,cAAA;IACA,mBAAA;EhByrCF;EgB1nCQ;IAhEN,cAAA;IACA,UAAA;EhB6rCF;EgB9nCQ;IAhEN,cAAA;IACA,mBAAA;EhBisCF;EgBloCQ;IAhEN,cAAA;IACA,mBAAA;EhBqsCF;EgBtoCQ;IAhEN,cAAA;IACA,WAAA;EhBysCF;EgBloCU;IAxDV,cAAA;EhB6rCA;EgBroCU;IAxDV,wBAAA;EhBgsCA;EgBxoCU;IAxDV,yBAAA;EhBmsCA;EgB3oCU;IAxDV,gBAAA;EhBssCA;EgB9oCU;IAxDV,yBAAA;EhBysCA;EgBjpCU;IAxDV,yBAAA;EhB4sCA;EgBppCU;IAxDV,gBAAA;EhB+sCA;EgBvpCU;IAxDV,yBAAA;EhBktCA;EgB1pCU;IAxDV,yBAAA;EhBqtCA;EgB7pCU;IAxDV,gBAAA;EhBwtCA;EgBhqCU;IAxDV,yBAAA;EhB2tCA;EgBnqCU;IAxDV,yBAAA;EhB8tCA;EgB3pCM;;IAEE,gBAAA;EhB6pCR;EgB1pCM;;IAEE,gBAAA;EhB4pCR;EgBnqCM;;IAEE,sBAAA;EhBqqCR;EgBlqCM;;IAEE,sBAAA;EhBoqCR;EgB3qCM;;IAEE,qBAAA;EhB6qCR;EgB1qCM;;IAEE,qBAAA;EhB4qCR;EgBnrCM;;IAEE,mBAAA;EhBqrCR;EgBlrCM;;IAEE,mBAAA;EhBorCR;EgB3rCM;;IAEE,qBAAA;EhB6rCR;EgB1rCM;;IAEE,qBAAA;EhB4rCR;EgBnsCM;;IAEE,mBAAA;EhBqsCR;EgBlsCM;;IAEE,mBAAA;EhBosCR;AACF;Ac/vCI;EEUE;IACE,YAAA;EhBwvCN;EgBrvCI;IApCJ,cAAA;IACA,WAAA;EhB4xCA;EgB9wCA;IACE,cAAA;IACA,WAAA;EhBgxCF;EgBlxCA;IACE,cAAA;IACA,UAAA;EhBoxCF;EgBtxCA;IACE,cAAA;IACA,mBAAA;EhBwxCF;EgB1xCA;IACE,cAAA;IACA,UAAA;EhB4xCF;EgB9xCA;IACE,cAAA;IACA,UAAA;EhBgyCF;EgBlyCA;IACE,cAAA;IACA,mBAAA;EhBoyCF;EgBrwCI;IAhDJ,cAAA;IACA,WAAA;EhBwzCA;EgBnwCQ;IAhEN,cAAA;IACA,kBAAA;EhBs0CF;EgBvwCQ;IAhEN,cAAA;IACA,mBAAA;EhB00CF;EgB3wCQ;IAhEN,cAAA;IACA,UAAA;EhB80CF;EgB/wCQ;IAhEN,cAAA;IACA,mBAAA;EhBk1CF;EgBnxCQ;IAhEN,cAAA;IACA,mBAAA;EhBs1CF;EgBvxCQ;IAhEN,cAAA;IACA,UAAA;EhB01CF;EgB3xCQ;IAhEN,cAAA;IACA,mBAAA;EhB81CF;EgB/xCQ;IAhEN,cAAA;IACA,mBAAA;EhBk2CF;EgBnyCQ;IAhEN,cAAA;IACA,UAAA;EhBs2CF;EgBvyCQ;IAhEN,cAAA;IACA,mBAAA;EhB02CF;EgB3yCQ;IAhEN,cAAA;IACA,mBAAA;EhB82CF;EgB/yCQ;IAhEN,cAAA;IACA,WAAA;EhBk3CF;EgB3yCU;IAxDV,cAAA;EhBs2CA;EgB9yCU;IAxDV,wBAAA;EhBy2CA;EgBjzCU;IAxDV,yBAAA;EhB42CA;EgBpzCU;IAxDV,gBAAA;EhB+2CA;EgBvzCU;IAxDV,yBAAA;EhBk3CA;EgB1zCU;IAxDV,yBAAA;EhBq3CA;EgB7zCU;IAxDV,gBAAA;EhBw3CA;EgBh0CU;IAxDV,yBAAA;EhB23CA;EgBn0CU;IAxDV,yBAAA;EhB83CA;EgBt0CU;IAxDV,gBAAA;EhBi4CA;EgBz0CU;IAxDV,yBAAA;EhBo4CA;EgB50CU;IAxDV,yBAAA;EhBu4CA;EgBp0CM;;IAEE,gBAAA;EhBs0CR;EgBn0CM;;IAEE,gBAAA;EhBq0CR;EgB50CM;;IAEE,sBAAA;EhB80CR;EgB30CM;;IAEE,sBAAA;EhB60CR;EgBp1CM;;IAEE,qBAAA;EhBs1CR;EgBn1CM;;IAEE,qBAAA;EhBq1CR;EgB51CM;;IAEE,mBAAA;EhB81CR;EgB31CM;;IAEE,mBAAA;EhB61CR;EgBp2CM;;IAEE,qBAAA;EhBs2CR;EgBn2CM;;IAEE,qBAAA;EhBq2CR;EgB52CM;;IAEE,mBAAA;EhB82CR;EgB32CM;;IAEE,mBAAA;EhB62CR;AACF;Acx6CI;EEUE;IACE,YAAA;EhBi6CN;EgB95CI;IApCJ,cAAA;IACA,WAAA;EhBq8CA;EgBv7CA;IACE,cAAA;IACA,WAAA;EhBy7CF;EgB37CA;IACE,cAAA;IACA,UAAA;EhB67CF;EgB/7CA;IACE,cAAA;IACA,mBAAA;EhBi8CF;EgBn8CA;IACE,cAAA;IACA,UAAA;EhBq8CF;EgBv8CA;IACE,cAAA;IACA,UAAA;EhBy8CF;EgB38CA;IACE,cAAA;IACA,mBAAA;EhB68CF;EgB96CI;IAhDJ,cAAA;IACA,WAAA;EhBi+CA;EgB56CQ;IAhEN,cAAA;IACA,kBAAA;EhB++CF;EgBh7CQ;IAhEN,cAAA;IACA,mBAAA;EhBm/CF;EgBp7CQ;IAhEN,cAAA;IACA,UAAA;EhBu/CF;EgBx7CQ;IAhEN,cAAA;IACA,mBAAA;EhB2/CF;EgB57CQ;IAhEN,cAAA;IACA,mBAAA;EhB+/CF;EgBh8CQ;IAhEN,cAAA;IACA,UAAA;EhBmgDF;EgBp8CQ;IAhEN,cAAA;IACA,mBAAA;EhBugDF;EgBx8CQ;IAhEN,cAAA;IACA,mBAAA;EhB2gDF;EgB58CQ;IAhEN,cAAA;IACA,UAAA;EhB+gDF;EgBh9CQ;IAhEN,cAAA;IACA,mBAAA;EhBmhDF;EgBp9CQ;IAhEN,cAAA;IACA,mBAAA;EhBuhDF;EgBx9CQ;IAhEN,cAAA;IACA,WAAA;EhB2hDF;EgBp9CU;IAxDV,cAAA;EhB+gDA;EgBv9CU;IAxDV,wBAAA;EhBkhDA;EgB19CU;IAxDV,yBAAA;EhBqhDA;EgB79CU;IAxDV,gBAAA;EhBwhDA;EgBh+CU;IAxDV,yBAAA;EhB2hDA;EgBn+CU;IAxDV,yBAAA;EhB8hDA;EgBt+CU;IAxDV,gBAAA;EhBiiDA;EgBz+CU;IAxDV,yBAAA;EhBoiDA;EgB5+CU;IAxDV,yBAAA;EhBuiDA;EgB/+CU;IAxDV,gBAAA;EhB0iDA;EgBl/CU;IAxDV,yBAAA;EhB6iDA;EgBr/CU;IAxDV,yBAAA;EhBgjDA;EgB7+CM;;IAEE,gBAAA;EhB++CR;EgB5+CM;;IAEE,gBAAA;EhB8+CR;EgBr/CM;;IAEE,sBAAA;EhBu/CR;EgBp/CM;;IAEE,sBAAA;EhBs/CR;EgB7/CM;;IAEE,qBAAA;EhB+/CR;EgB5/CM;;IAEE,qBAAA;EhB8/CR;EgBrgDM;;IAEE,mBAAA;EhBugDR;EgBpgDM;;IAEE,mBAAA;EhBsgDR;EgB7gDM;;IAEE,qBAAA;EhB+gDR;EgB5gDM;;IAEE,qBAAA;EhB8gDR;EgBrhDM;;IAEE,mBAAA;EhBuhDR;EgBphDM;;IAEE,mBAAA;EhBshDR;AACF;AcjlDI;EEUE;IACE,YAAA;EhB0kDN;EgBvkDI;IApCJ,cAAA;IACA,WAAA;EhB8mDA;EgBhmDA;IACE,cAAA;IACA,WAAA;EhBkmDF;EgBpmDA;IACE,cAAA;IACA,UAAA;EhBsmDF;EgBxmDA;IACE,cAAA;IACA,mBAAA;EhB0mDF;EgB5mDA;IACE,cAAA;IACA,UAAA;EhB8mDF;EgBhnDA;IACE,cAAA;IACA,UAAA;EhBknDF;EgBpnDA;IACE,cAAA;IACA,mBAAA;EhBsnDF;EgBvlDI;IAhDJ,cAAA;IACA,WAAA;EhB0oDA;EgBrlDQ;IAhEN,cAAA;IACA,kBAAA;EhBwpDF;EgBzlDQ;IAhEN,cAAA;IACA,mBAAA;EhB4pDF;EgB7lDQ;IAhEN,cAAA;IACA,UAAA;EhBgqDF;EgBjmDQ;IAhEN,cAAA;IACA,mBAAA;EhBoqDF;EgBrmDQ;IAhEN,cAAA;IACA,mBAAA;EhBwqDF;EgBzmDQ;IAhEN,cAAA;IACA,UAAA;EhB4qDF;EgB7mDQ;IAhEN,cAAA;IACA,mBAAA;EhBgrDF;EgBjnDQ;IAhEN,cAAA;IACA,mBAAA;EhBorDF;EgBrnDQ;IAhEN,cAAA;IACA,UAAA;EhBwrDF;EgBznDQ;IAhEN,cAAA;IACA,mBAAA;EhB4rDF;EgB7nDQ;IAhEN,cAAA;IACA,mBAAA;EhBgsDF;EgBjoDQ;IAhEN,cAAA;IACA,WAAA;EhBosDF;EgB7nDU;IAxDV,cAAA;EhBwrDA;EgBhoDU;IAxDV,wBAAA;EhB2rDA;EgBnoDU;IAxDV,yBAAA;EhB8rDA;EgBtoDU;IAxDV,gBAAA;EhBisDA;EgBzoDU;IAxDV,yBAAA;EhBosDA;EgB5oDU;IAxDV,yBAAA;EhBusDA;EgB/oDU;IAxDV,gBAAA;EhB0sDA;EgBlpDU;IAxDV,yBAAA;EhB6sDA;EgBrpDU;IAxDV,yBAAA;EhBgtDA;EgBxpDU;IAxDV,gBAAA;EhBmtDA;EgB3pDU;IAxDV,yBAAA;EhBstDA;EgB9pDU;IAxDV,yBAAA;EhBytDA;EgBtpDM;;IAEE,gBAAA;EhBwpDR;EgBrpDM;;IAEE,gBAAA;EhBupDR;EgB9pDM;;IAEE,sBAAA;EhBgqDR;EgB7pDM;;IAEE,sBAAA;EhB+pDR;EgBtqDM;;IAEE,qBAAA;EhBwqDR;EgBrqDM;;IAEE,qBAAA;EhBuqDR;EgB9qDM;;IAEE,mBAAA;EhBgrDR;EgB7qDM;;IAEE,mBAAA;EhB+qDR;EgBtrDM;;IAEE,qBAAA;EhBwrDR;EgBrrDM;;IAEE,qBAAA;EhBurDR;EgB9rDM;;IAEE,mBAAA;EhBgsDR;EgB7rDM;;IAEE,mBAAA;EhB+rDR;AACF;AiBrzDA;EAEE,8BAAA;EACA,2BAAA;EACA,+BAAA;EACA,4BAAA;EAEA,0CAAA;EACA,gCAAA;EACA,+CAAA;EACA,iCAAA;EACA,kDAAA;EACA,+DAAA;EACA,iDAAA;EACA,6DAAA;EACA,gDAAA;EACA,8DAAA;EAEA,WAAA;EACA,mBXkYO;EWjYP,mBXusB4B;EWtsB5B,0CAAA;AjBozDF;AiB7yDE;EACE,sBAAA;EAEA,qFAAA;EACA,oCAAA;EACA,2CX+sB0B;EW9sB1B,2GAAA;AjB8yDJ;AiB3yDE;EACE,uBAAA;AjB6yDJ;AiB1yDE;EACE,sBAAA;AjB4yDJ;;AiBxyDA;EACE,+DAAA;AjB2yDF;;AiBpyDA;EACE,iBAAA;AjBuyDF;;AiB7xDE;EACE,wBAAA;AjBgyDJ;;AiBjxDE;EACE,sCAAA;AjBoxDJ;AiBjxDI;EACE,sCAAA;AjBmxDN;;AiB5wDE;EACE,sBAAA;AjB+wDJ;AiB5wDE;EACE,mBAAA;AjB8wDJ;;AiBpwDE;EACE,oDAAA;EACA,8CAAA;AjBuwDJ;;AiBjwDE;EACE,oDAAA;EACA,8CAAA;AjBowDJ;;AiB5vDA;EACE,oDAAA;EACA,8CAAA;AjB+vDF;;AiBvvDE;EACE,mDAAA;EACA,6CAAA;AjB0vDJ;;AkBt4DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlBk4DJ;;AkBp5DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlBg5DJ;;AkBl6DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlB85DJ;;AkBh7DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlB46DJ;;AkB97DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlB07DJ;;AkB58DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlBw8DJ;;AkB19DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlBs9DJ;;AkBx+DE;EAOE,sBAAA;EACA,sBAAA;EACA,gCAAA;EACA,8BAAA;EACA,8BAAA;EACA,6BAAA;EACA,6BAAA;EACA,4BAAA;EACA,4BAAA;EAEA,4BAAA;EACA,0CAAA;AlBo+DJ;;AiBn1DI;EACE,gBAAA;EACA,iCAAA;AjBs1DN;;Acj7DI;EGyFA;IACE,gBAAA;IACA,iCAAA;EjB41DJ;AACF;Acx7DI;EGyFA;IACE,gBAAA;IACA,iCAAA;EjBk2DJ;AACF;Ac97DI;EGyFA;IACE,gBAAA;IACA,iCAAA;EjBw2DJ;AACF;Acp8DI;EGyFA;IACE,gBAAA;IACA,iCAAA;EjB82DJ;AACF;Ac18DI;EGyFA;IACE,gBAAA;IACA,iCAAA;EjBo3DJ;AACF;AmBxhEA;EACE,qBbu2BsC;ANmrCxC;;AmBjhEA;EACE,oDAAA;EACA,uDAAA;EACA,gBAAA;EhB8QI,kBALI;EgBrQR,gBb+lB4B;ANm7C9B;;AmB9gEA;EACE,kDAAA;EACA,qDAAA;EhBoQI,kBALI;AHmxDV;;AmB9gEA;EACE,mDAAA;EACA,sDAAA;EhB8PI,mBALI;AHyxDV;;AoB/iEA;EACE,mBd+1BsC;EHrkBlC,kBALI;EiBjRR,gCd+1BsC;ANitCxC;;AqBrjEA;EACE,cAAA;EACA,WAAA;EACA,yBAAA;ElBwRI,eALI;EkBhRR,gBfkmB4B;EejmB5B,gBfymB4B;EexmB5B,2Bf43BsC;Ee33BtC,wBAAA;EAAA,qBAAA;EAAA,gBAAA;EACA,mCfq3BsC;Eep3BtC,4BAAA;EACA,2DAAA;EdGE,sCAAA;EeHE,wEDMJ;ArBmjEF;AsBrjEM;EDhBN;ICiBQ,gBAAA;EtBwjEN;AACF;AqBtjEE;EACE,gBAAA;ArBwjEJ;AqBtjEI;EACE,eAAA;ArBwjEN;AqBnjEE;EACE,2Bfs2BoC;Eer2BpC,mCfg2BoC;Ee/1BpC,qBf82BoC;Ee72BpC,UAAA;EAKE,kDfkhBkB;AN+hDxB;AqB7iEE;EAME,eAAA;EAMA,aAAA;EAKA,SAAA;ArBiiEJ;AqB5hEE;EACE,cAAA;EACA,UAAA;ArB8hEJ;AqB1hEE;EACE,gCf40BoC;Ee10BpC,UAAA;ArB2hEJ;AqB9hEE;EACE,gCf40BoC;Ee10BpC,UAAA;ArB2hEJ;AqBnhEE;EAEE,wCf8yBoC;Ee3yBpC,UAAA;ArBkhEJ;AqB9gEE;EACE,yBAAA;EACA,0BAAA;EACA,2BforB0B;EeprB1B,0BforB0B;EenrB1B,2BfsyBoC;EiBp4BtC,uCjBqiCgC;Eer8B9B,oBAAA;EACA,qBAAA;EACA,mBAAA;EACA,eAAA;EACA,+CfgsB0B;Ee/rB1B,gBAAA;ECzFE,6ID0FF;EC1FE,qID0FF;ArBghEJ;AqB5hEE;EACE,yBAAA;EACA,0BAAA;EACA,2BforB0B;EeprB1B,0BforB0B;EenrB1B,2BfsyBoC;EiBp4BtC,uCjBqiCgC;Eer8B9B,oBAAA;EACA,qBAAA;EACA,mBAAA;EACA,eAAA;EACA,+CfgsB0B;Ee/rB1B,gBAAA;ECzFE,qID0FF;ArBghEJ;AsBtmEM;ED0EJ;ICzEM,wBAAA;IAAA,gBAAA;EtBymEN;EqBhiEA;ICzEM,gBAAA;EtBymEN;AACF;AqBlhEE;EACE,wCf47B8B;ANwlClC;AqBrhEE;EACE,wCf47B8B;ANwlClC;;AqB3gEA;EACE,cAAA;EACA,WAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBfwf4B;Eevf5B,2Bf2xBsC;Ee1xBtC,6BAAA;EACA,yBAAA;EACA,sCAAA;ArB8gEF;AqB5gEE;EACE,UAAA;ArB8gEJ;AqB3gEE;EAEE,gBAAA;EACA,eAAA;ArB4gEJ;;AqBjgEA;EACE,mEf4wBsC;Ee3wBtC,uBAAA;ElByII,mBALI;EIvQN,yCAAA;APyoEJ;AqBlgEE;EACE,uBAAA;EACA,wBAAA;EACA,0BfooB0B;EepoB1B,yBfooB0B;ANg4C9B;AqBvgEE;EACE,uBAAA;EACA,wBAAA;EACA,0BfooB0B;EepoB1B,yBfooB0B;ANg4C9B;;AqBhgEA;EACE,iEfgwBsC;Ee/vBtC,oBAAA;ElB4HI,kBALI;EIvQN,yCAAA;APqpEJ;AqBjgEE;EACE,oBAAA;EACA,qBAAA;EACA,wBf2nB0B;Ee3nB1B,uBf2nB0B;ANw4C9B;AqBtgEE;EACE,oBAAA;EACA,qBAAA;EACA,wBf2nB0B;Ee3nB1B,uBf2nB0B;ANw4C9B;;AqB3/DE;EACE,oEf6uBoC;ANixCxC;AqB3/DE;EACE,mEf0uBoC;ANmxCxC;AqB1/DE;EACE,iEfuuBoC;ANqxCxC;;AqBv/DA;EACE,WfquBsC;EepuBtC,gEf8tBsC;Ee7tBtC,iBfilB4B;ANy6C9B;AqBx/DE;EACE,eAAA;ArB0/DJ;AqBv/DE;EACE,oBAAA;EdvLA,sCAAA;APirEJ;AqBt/DE;EACE,oBAAA;Ed5LA,sCAAA;APqrEJ;AqBr/DE;EAAoB,+Df8sBkB;AN0yCxC;AqBv/DE;EAAoB,6Df8sBkB;AN4yCxC;;AwBzsEA;EACE,wPAAA;EAEA,cAAA;EACA,WAAA;EACA,0CAAA;ErBqRI,eALI;EqB7QR,gBlB+lB4B;EkB9lB5B,gBlBsmB4B;EkBrmB5B,2BlBy3BsC;EkBx3BtC,wBAAA;EAAA,qBAAA;EAAA,gBAAA;EACA,mClBk3BsC;EkBj3BtC,mFAAA;EACA,4BAAA;EACA,yClB+9BkC;EkB99BlC,0BlB+9BkC;EkB99BlC,2DAAA;EjBHE,sCAAA;EeHE,wEESJ;AxBysEF;AsB9sEM;EEfN;IFgBQ,gBAAA;EtBitEN;AACF;AwB5sEE;EACE,qBlBs3BoC;EkBr3BpC,UAAA;EAKE,kDlBi+B4B;ANyuClC;AwBtsEE;EAEE,sBlB6uB0B;EkB5uB1B,sBAAA;AxBusEJ;AwBpsEE;EAEE,wClBu1BoC;AN82CxC;AwBhsEE;EACE,kBAAA;EACA,uCAAA;AxBksEJ;;AwB9rEA;EACE,oBlBsuB4B;EkBruB5B,uBlBquB4B;EkBpuB5B,oBlBquB4B;EHlgBxB,mBALI;EIvQN,yCAAA;AP4uEJ;;AwB9rEA;EACE,mBlBkuB4B;EkBjuB5B,sBlBiuB4B;EkBhuB5B,kBlBiuB4B;EHtgBxB,kBALI;EIvQN,yCAAA;APovEJ;;AwB5rEI;EACE,wPAAA;AxB+rEN;;AyBvwEA;EACE,cAAA;EACA,kBnBq6BwC;EmBp6BxC,mBnBq6BwC;EmBp6BxC,uBnBq6BwC;ANq2C1C;AyBxwEE;EACE,WAAA;EACA,mBAAA;AzB0wEJ;;AyBtwEA;EACE,oBnB25BwC;EmB15BxC,eAAA;EACA,iBAAA;AzBywEF;AyBvwEE;EACE,YAAA;EACA,oBAAA;EACA,cAAA;AzBywEJ;;AyBrwEA;EACE,qCAAA;EAEA,cAAA;EACA,UnB04BwC;EmBz4BxC,WnBy4BwC;EmBx4BxC,kBAAA;EACA,mBAAA;EACA,wBAAA;EAAA,qBAAA;EAAA,gBAAA;EACA,yCAAA;EACA,+CAAA;EACA,4BAAA;EACA,2BAAA;EACA,wBAAA;EACA,2DnB24BwC;EmB14BxC,iCAAA;EAAA,mBAAA;EAAA,yBAAA;AzBuwEF;AyBpwEE;ElB3BE,qBAAA;APkyEJ;AyBnwEE;EAEE,kBnBm4BsC;ANi4C1C;AyBjwEE;EACE,uBnB03BsC;ANy4C1C;AyBhwEE;EACE,qBnBs1BoC;EmBr1BpC,UAAA;EACA,kDnB8foB;ANowDxB;AyB/vEE;EACE,yBnB5BM;EmB6BN,qBnB7BM;AN8xEV;AyB/vEI;EAII,uPAAA;AzB8vER;AyB1vEI;EAII,+JAAA;AzByvER;AyBpvEE;EACE,yBnBjDM;EmBkDN,qBnBlDM;EmBuDJ,iPAAA;AzBkvEN;AyB9uEE;EACE,oBAAA;EACA,YAAA;EACA,YnBk2BuC;AN84C3C;AyBzuEI;EACE,eAAA;EACA,YnBy1BqC;ANk5C3C;;AyB7tEA;EACE,mBnBo1BgC;AN44ClC;AyB9tEE;EACE,2KAAA;EAEA,UnB80B8B;EmB70B9B,mBAAA;EACA,0CAAA;EACA,gCAAA;ElBjHA,kBAAA;EeHE,iDGsHF;AzB+tEJ;AsBj1EM;EG0GJ;IHzGM,gBAAA;EtBo1EN;AACF;AyBluEI;EACE,6JAAA;AzBouEN;AyBjuEI;EACE,iCnB60B4B;EmBx0B1B,0JAAA;AzB+tER;AyB1tEE;EACE,oBnBwzB8B;EmBvzB9B,eAAA;AzB4tEJ;AyB1tEI;EACE,oBAAA;EACA,cAAA;AzB4tEN;;AyBvtEA;EACE,qBAAA;EACA,kBnBsyBgC;ANo7ClC;;AyBvtEA;EACE,kBAAA;EACA,sBAAA;EACA,oBAAA;AzB0tEF;AyBttEI;EACE,oBAAA;EACA,YAAA;EACA,anBspBwB;ANkkD9B;;AyBjtEI;EACE,iLAAA;AzBotEN;;A0Bv4EA;EACE,WAAA;EACA,cAAA;EACA,UAAA;EACA,wBAAA;EAAA,qBAAA;EAAA,gBAAA;EACA,6BAAA;A1B04EF;A0Bx4EE;EACE,UAAA;A1B04EJ;A0Bt4EI;EAA0B,kEpB8gCa;AN23C3C;A0Bx4EI;EAA0B,kEpB6gCa;AN83C3C;A0Bx4EE;EACE,SAAA;A1B04EJ;A0Bv4EE;EACE,WpB+/BuC;EoB9/BvC,YpB8/BuC;EoB7/BvC,oBAAA;EACA,wBAAA;EAAA,gBAAA;EH1BF,yBjBkCQ;EoBNN,SpB6/BuC;EC1gCvC,mBAAA;EeHE,oHImBF;EJnBE,4GImBF;A1Bw4EJ;AsBv5EM;EIMJ;IJLM,wBAAA;IAAA,gBAAA;EtB05EN;AACF;A0B34EI;EHjCF,yBjB8hCyC;ANi5C3C;A0Bz4EE;EACE,WpBw+B8B;EoBv+B9B,cpBw+B8B;EoBv+B9B,kBAAA;EACA,epBu+B8B;EoBt+B9B,wCpBu+B8B;EoBt+B9B,yBAAA;EnB7BA,mBAAA;APy6EJ;A0Bv4EE;EACE,WpBo+BuC;EoBn+BvC,YpBm+BuC;EoBl+BvC,qBAAA;EAAA,gBAAA;EHpDF,yBjBkCQ;EoBoBN,SpBm+BuC;EC1gCvC,mBAAA;EeHE,iHI6CF;EJ7CE,4GI6CF;A1Bw4EJ;AsBj7EM;EIiCJ;IJhCM,qBAAA;IAAA,gBAAA;EtBo7EN;AACF;A0B34EI;EH3DF,yBjB8hCyC;AN26C3C;A0Bz4EE;EACE,WpB88B8B;EoB78B9B,cpB88B8B;EoB78B9B,kBAAA;EACA,epB68B8B;EoB58B9B,wCpB68B8B;EoB58B9B,yBAAA;EnBvDA,mBAAA;APm8EJ;A0Bv4EE;EACE,oBAAA;A1By4EJ;A0Bv4EI;EACE,2CpBg9BqC;ANy7C3C;A0Bt4EI;EACE,2CpB48BqC;AN47C3C;;A2B/9EA;EACE,kBAAA;A3Bk+EF;A2Bh+EE;;;EAGE,uDrBwiCoC;EqBviCpC,2DrBuiCoC;EqBtiCpC,iBrBuiCoC;AN27CxC;A2B/9EE;EACE,kBAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;EACA,YAAA;EACA,qBAAA;EACA,gBAAA;EACA,iBAAA;EACA,uBAAA;EACA,mBAAA;EACA,oBAAA;EACA,gDAAA;EACA,qBAAA;ELRE,gEKSF;A3Bi+EJ;AsBt+EM;EKTJ;ILUM,gBAAA;EtBy+EN;AACF;A2Bn+EE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AA;AxEk0OZ;;AwEz0OQ;EAOI,sBAAA;AxEs0OZ;;AwE70OQ;EAOI,sBAAA;AxE00OZ;;AwEj1OQ;EAOI,sBAAA;AxE80OZ;;AwEr1OQ;EAOI,uBAAA;AxEk1OZ;;AwEz1OQ;EAOI,uBAAA;AxEs1OZ;;AwE71OQ;EAOI,2BAAA;AxE01OZ;;AwEj2OQ;EAOI,wBAAA;AxE81OZ;;AwEr2OQ;EAOI,4BAAA;AxEk2OZ;;AwEz2OQ;EAOI,yBAAA;AxEs2OZ;;AwE72OQ;EAOI,8BAAA;AxE02OZ;;AwEj3OQ;EAOI,iCAAA;AxE82OZ;;AwEr3OQ;EAOI,sCAAA;AxEk3OZ;;AwEz3OQ;EAOI,yCAAA;AxEs3OZ;;AwE73OQ;EAOI,uBAAA;AxE03OZ;;AwEj4OQ;EAOI,uBAAA;AxE83OZ;;AwEr4OQ;EAOI,yBAAA;AxEk4OZ;;AwEz4OQ;EAOI,yBAAA;AxEs4OZ;;AwE74OQ;EAOI,0BAAA;AxE04OZ;;AwEj5OQ;EAOI,4BAAA;AxE84OZ;;AwEr5OQ;EAOI,kCAAA;AxEk5OZ;;AwEz5OQ;EAOI,sCAAA;AxEs5OZ;;AwE75OQ;EAOI,oCAAA;AxE05OZ;;AwEj6OQ;EAOI,kCAAA;AxE85OZ;;AwEr6OQ;EAOI,yCAAA;AxEk6OZ;;AwEz6OQ;EAOI,wCAAA;AxEs6OZ;;AwE76OQ;EAOI,wCAAA;AxE06OZ;;AwEj7OQ;EAOI,kCAAA;AxE86OZ;;AwEr7OQ;EAOI,gCAAA;AxEk7OZ;;AwEz7OQ;EAOI,8BAAA;AxEs7OZ;;AwE77OQ;EAOI,gCAAA;AxE07OZ;;AwEj8OQ;EAOI,+BAAA;AxE87OZ;;AwEr8OQ;EAOI,oCAAA;AxEk8OZ;;AwEz8OQ;EAOI,kCAAA;AxEs8OZ;;AwE78OQ;EAOI,gCAAA;AxE08OZ;;AwEj9OQ;EAOI,uCAAA;AxE88OZ;;AwEr9OQ;EAOI,sCAAA;AxEk9OZ;;AwEz9OQ;EAOI,iCAAA;AxEs9OZ;;AwE79OQ;EAOI,2BAAA;AxE09OZ;;AwEj+OQ;EAOI,iCAAA;AxE89OZ;;AwEr+OQ;EAOI,+BAAA;AxEk+OZ;;AwEz+OQ;EAOI,6BAAA;AxEs+OZ;;AwE7+OQ;EAOI,+BAAA;AxE0+OZ;;AwEj/OQ;EAOI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AA;ExEs3SV;EwE73SM;IAOI,sCAAA;ExEy3SV;EwEh4SM;IAOI,yCAAA;ExE43SV;EwEn4SM;IAOI,uBAAA;ExE+3SV;EwEt4SM;IAOI,uBAAA;ExEk4SV;EwEz4SM;IAOI,yBAAA;ExEq4SV;EwE54SM;IAOI,yBAAA;ExEw4SV;EwE/4SM;IAOI,0BAAA;ExE24SV;EwEl5SM;IAOI,4BAAA;ExE84SV;EwEr5SM;IAOI,kCAAA;ExEi5SV;EwEx5SM;IAOI,sCAAA;ExEo5SV;EwE35SM;IAOI,oCAAA;ExEu5SV;EwE95SM;IAOI,kCAAA;ExE05SV;EwEj6SM;IAOI,yCAAA;ExE65SV;EwEp6SM;IAOI,wCAAA;ExEg6SV;EwEv6SM;IAOI,wCAAA;ExEm6SV;EwE16SM;IAOI,kCAAA;ExEs6SV;EwE76SM;IAOI,gCAAA;ExEy6SV;EwEh7SM;IAOI,8BAAA;ExE46SV;EwEn7SM;IAOI,gCAAA;ExE+6SV;EwEt7SM;IAOI,+BAAA;ExEk7SV;EwEz7SM;IAOI,oCAAA;ExEq7SV;EwE57SM;IAOI,kCAAA;ExEw7SV;EwE/7SM;IAOI,gCAAA;ExE27SV;EwEl8SM;IAOI,uCAAA;ExE87SV;EwEr8SM;IAOI,sCAAA;ExEi8SV;EwEx8SM;IAOI,iCAAA;ExEo8SV;EwE38SM;IAOI,2BAAA;ExEu8SV;EwE98SM;IAOI,iCAAA;ExE08SV;EwEj9SM;IAOI,+BAAA;ExE68SV;EwEp9SM;IAOI,6BAAA;ExEg9SV;EwEv9SM;IAOI,+BAAA;ExEm9SV;EwE19SM;IAOI,8BAAA;ExEs9SV;EwE79SM;IAOI,oBAAA;ExEy9SV;EwEh+SM;IAOI,mBAAA;ExE49SV;EwEn+SM;IAOI,mBAAA;ExE+9SV;EwEt+SM;IAOI,mBAAA;ExEk+SV;EwEz+SM;IAOI,mBAAA;ExEq+SV;EwE5+SM;IAOI,mBAAA;ExEw+SV;EwE/+SM;IAOI,mBAAA;ExE2+SV;EwEl/SM;IAOI,mBAAA;ExE8+SV;EwEr/SM;IAOI,oBAAA;ExEi/SV;EwEx/SM;IAOI,0BAAA;ExEo/SV;EwE3/SM;IAOI,yBAAA;ExEu/SV;EwE9/SM;IAOI,uBAAA;ExE0/SV;E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V;EwE/3TM;IAOI,yBAAA;ExE23TV;EwEl4TM;IAOI,wBAAA;ExE83TV;EwEr4TM;IAOI,+BAAA;ExEi4TV;EwEx4TM;IAOI,yBAAA;ExEo4TV;EwE34TM;IAOI,6BAAA;ExEu4TV;EwE94TM;IAOI,8BAAA;ExE04TV;EwEj5TM;IAOI,wBAAA;ExE64TV;EwEp5TM;IAOI,+BAAA;ExEg5TV;EwEv5TM;IAOI,wBAAA;ExEm5TV;EwE15TM;IAOI,yBAAA;ExEs5TV;EwE75TM;IAOI,8BAAA;ExEy5TV;EwEh6TM;IAOI,iCAAA;ExE45TV;EwEn6TM;IAOI,sCAAA;ExE+5TV;EwEt6TM;IAOI,yCAAA;ExEk6TV;EwEz6TM;IAOI,uBAAA;ExEq6TV;EwE56TM;IAOI,uBAAA;ExEw6TV;EwE/6TM;IAOI,yBAAA;ExE26TV;EwEl7TM;IAOI,yBAAA;ExE86TV;EwEr7TM;IAOI,0BAAA;ExEi7TV;EwEx7TM;IAOI,4BAAA;ExEo7TV;EwE37TM;IAOI,kCAAA;ExEu7TV;EwE97TM;IAOI,sCAAA;ExE07TV;EwEj8TM;IAOI,oCAAA;ExE67TV;EwEp8TM;IAOI,kCAAA;ExEg8TV;EwEv8TM;IAOI,yCAAA;ExEm8TV;EwE18TM;IAOI,wCAAA;ExEs8TV;EwE78TM;IAOI,wCAAA;ExEy8TV;EwEh9TM;IAOI,kCAAA;ExE48TV;EwEn9TM;IAOI,gCAAA;ExE+8TV;EwEt9TM;IAOI,8BAAA;ExEk9TV;EwEz9TM;IAOI,gCAAA;ExEq9TV;EwE59TM;IAOI,+BAAA;ExEw9TV;EwE/9TM;IAOI,oCAAA;ExE29TV;EwEl+TM;IAOI,kCAAA;ExE89TV;EwEr+TM;IAOI,gCAAA;ExEi+TV;EwEx+TM;IAOI,uCAAA;ExEo+TV;EwE3+TM;IAOI,sCAAA;ExEu+TV;EwE9+TM;IAOI,iCAAA;ExE0+TV;EwEj/TM;IAOI,2BAAA;ExE6+TV;EwEp/TM;IAOI,iCAAA;ExEg/TV;EwEv/TM;IAOI,+BAAA;ExEm/TV;EwE1/TM;IAOI,6BAAA;ExEs/TV;EwE7/TM;IAOI,+BAAA;ExEy/TV;EwEhgUM;IAOI,8BAAA;ExE4/TV;EwEngUM;IA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","file":"bootstrap.css","sourcesContent":["@charset \"UTF-8\";\n/*!\n * Bootstrap v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n:root,\n[data-bs-theme=light] {\n --bs-blue: #0d6efd;\n --bs-indigo: #6610f2;\n --bs-purple: #6f42c1;\n --bs-pink: #d63384;\n --bs-red: #dc3545;\n --bs-orange: #fd7e14;\n --bs-yellow: #ffc107;\n --bs-green: #198754;\n --bs-teal: #20c997;\n --bs-cyan: #0dcaf0;\n --bs-black: #000;\n --bs-white: #fff;\n --bs-gray: #6c757d;\n --bs-gray-dark: #343a40;\n --bs-gray-100: #f8f9fa;\n --bs-gray-200: #e9ecef;\n --bs-gray-300: #dee2e6;\n --bs-gray-400: #ced4da;\n --bs-gray-500: #adb5bd;\n --bs-gray-600: #6c757d;\n --bs-gray-700: #495057;\n --bs-gray-800: #343a40;\n --bs-gray-900: #212529;\n --bs-primary: #0d6efd;\n --bs-secondary: #6c757d;\n --bs-success: #198754;\n --bs-info: #0dcaf0;\n --bs-warning: #ffc107;\n --bs-danger: #dc3545;\n --bs-light: #f8f9fa;\n --bs-dark: #212529;\n --bs-primary-rgb: 13, 110, 253;\n --bs-secondary-rgb: 108, 117, 125;\n --bs-success-rgb: 25, 135, 84;\n --bs-info-rgb: 13, 202, 240;\n --bs-warning-rgb: 255, 193, 7;\n --bs-danger-rgb: 220, 53, 69;\n --bs-light-rgb: 248, 249, 250;\n --bs-dark-rgb: 33, 37, 41;\n --bs-primary-text-emphasis: #052c65;\n --bs-secondary-text-emphasis: #2b2f32;\n --bs-success-text-emphasis: #0a3622;\n --bs-info-text-emphasis: #055160;\n --bs-warning-text-emphasis: #664d03;\n --bs-danger-text-emphasis: #58151c;\n --bs-light-text-emphasis: #495057;\n --bs-dark-text-emphasis: #495057;\n --bs-primary-bg-subtle: #cfe2ff;\n --bs-secondary-bg-subtle: #e2e3e5;\n --bs-success-bg-subtle: #d1e7dd;\n --bs-info-bg-subtle: #cff4fc;\n --bs-warning-bg-subtle: #fff3cd;\n --bs-danger-bg-subtle: #f8d7da;\n --bs-light-bg-subtle: #fcfcfd;\n --bs-dark-bg-subtle: #ced4da;\n --bs-primary-border-subtle: #9ec5fe;\n --bs-secondary-border-subtle: #c4c8cb;\n --bs-success-border-subtle: #a3cfbb;\n --bs-info-border-subtle: #9eeaf9;\n --bs-warning-border-subtle: #ffe69c;\n --bs-danger-border-subtle: #f1aeb5;\n --bs-light-border-subtle: #e9ecef;\n --bs-dark-border-subtle: #adb5bd;\n --bs-white-rgb: 255, 255, 255;\n --bs-black-rgb: 0, 0, 0;\n --bs-font-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));\n --bs-body-font-family: var(--bs-font-sans-serif);\n --bs-body-font-size: 1rem;\n --bs-body-font-weight: 400;\n --bs-body-line-height: 1.5;\n --bs-body-color: #212529;\n --bs-body-color-rgb: 33, 37, 41;\n --bs-body-bg: #fff;\n --bs-body-bg-rgb: 255, 255, 255;\n --bs-emphasis-color: #000;\n --bs-emphasis-color-rgb: 0, 0, 0;\n --bs-secondary-color: rgba(33, 37, 41, 0.75);\n --bs-secondary-color-rgb: 33, 37, 41;\n --bs-secondary-bg: #e9ecef;\n --bs-secondary-bg-rgb: 233, 236, 239;\n --bs-tertiary-color: rgba(33, 37, 41, 0.5);\n --bs-tertiary-color-rgb: 33, 37, 41;\n --bs-tertiary-bg: #f8f9fa;\n --bs-tertiary-bg-rgb: 248, 249, 250;\n --bs-heading-color: inherit;\n --bs-link-color: #0d6efd;\n --bs-link-color-rgb: 13, 110, 253;\n --bs-link-decoration: underline;\n --bs-link-hover-color: #0a58ca;\n --bs-link-hover-color-rgb: 10, 88, 202;\n --bs-code-color: #d63384;\n --bs-highlight-color: #212529;\n --bs-highlight-bg: #fff3cd;\n --bs-border-width: 1px;\n --bs-border-style: solid;\n --bs-border-color: #dee2e6;\n --bs-border-color-translucent: rgba(0, 0, 0, 0.175);\n --bs-border-radius: 0.375rem;\n --bs-border-radius-sm: 0.25rem;\n --bs-border-radius-lg: 0.5rem;\n --bs-border-radius-xl: 1rem;\n --bs-border-radius-xxl: 2rem;\n --bs-border-radius-2xl: var(--bs-border-radius-xxl);\n --bs-border-radius-pill: 50rem;\n --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);\n --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);\n --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);\n --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);\n --bs-focus-ring-width: 0.25rem;\n --bs-focus-ring-opacity: 0.25;\n --bs-focus-ring-color: rgba(13, 110, 253, 0.25);\n --bs-form-valid-color: #198754;\n --bs-form-valid-border-color: #198754;\n --bs-form-invalid-color: #dc3545;\n --bs-form-invalid-border-color: #dc3545;\n}\n\n[data-bs-theme=dark] {\n color-scheme: dark;\n --bs-body-color: #dee2e6;\n --bs-body-color-rgb: 222, 226, 230;\n --bs-body-bg: #212529;\n --bs-body-bg-rgb: 33, 37, 41;\n --bs-emphasis-color: #fff;\n --bs-emphasis-color-rgb: 255, 255, 255;\n --bs-secondary-color: rgba(222, 226, 230, 0.75);\n --bs-secondary-color-rgb: 222, 226, 230;\n --bs-secondary-bg: #343a40;\n --bs-secondary-bg-rgb: 52, 58, 64;\n --bs-tertiary-color: rgba(222, 226, 230, 0.5);\n --bs-tertiary-color-rgb: 222, 226, 230;\n --bs-tertiary-bg: #2b3035;\n --bs-tertiary-bg-rgb: 43, 48, 53;\n --bs-primary-text-emphasis: #6ea8fe;\n --bs-secondary-text-emphasis: #a7acb1;\n --bs-success-text-emphasis: #75b798;\n --bs-info-text-emphasis: #6edff6;\n --bs-warning-text-emphasis: #ffda6a;\n --bs-danger-text-emphasis: #ea868f;\n --bs-light-text-emphasis: #f8f9fa;\n --bs-dark-text-emphasis: #dee2e6;\n --bs-primary-bg-subtle: #031633;\n --bs-secondary-bg-subtle: #161719;\n --bs-success-bg-subtle: #051b11;\n --bs-info-bg-subtle: #032830;\n --bs-warning-bg-subtle: #332701;\n --bs-danger-bg-subtle: #2c0b0e;\n --bs-light-bg-subtle: #343a40;\n --bs-dark-bg-subtle: #1a1d20;\n --bs-primary-border-subtle: #084298;\n --bs-secondary-border-subtle: #41464b;\n --bs-success-border-subtle: #0f5132;\n --bs-info-border-subtle: #087990;\n --bs-warning-border-subtle: #997404;\n --bs-danger-border-subtle: #842029;\n --bs-light-border-subtle: #495057;\n --bs-dark-border-subtle: #343a40;\n --bs-heading-color: inherit;\n --bs-link-color: #6ea8fe;\n --bs-link-hover-color: #8bb9fe;\n --bs-link-color-rgb: 110, 168, 254;\n --bs-link-hover-color-rgb: 139, 185, 254;\n --bs-code-color: #e685b5;\n --bs-highlight-color: #dee2e6;\n --bs-highlight-bg: #664d03;\n --bs-border-color: #495057;\n --bs-border-color-translucent: rgba(255, 255, 255, 0.15);\n --bs-form-valid-color: #75b798;\n --bs-form-valid-border-color: #75b798;\n --bs-form-invalid-color: #ea868f;\n --bs-form-invalid-border-color: #ea868f;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n :root {\n scroll-behavior: smooth;\n }\n}\n\nbody {\n margin: 0;\n font-family: var(--bs-body-font-family);\n font-size: var(--bs-body-font-size);\n font-weight: var(--bs-body-font-weight);\n line-height: var(--bs-body-line-height);\n color: var(--bs-body-color);\n text-align: var(--bs-body-text-align);\n background-color: var(--bs-body-bg);\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nhr {\n margin: 1rem 0;\n color: inherit;\n border: 0;\n border-top: var(--bs-border-width) solid;\n opacity: 0.25;\n}\n\nh6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n font-weight: 500;\n line-height: 1.2;\n color: var(--bs-heading-color);\n}\n\nh1, .h1 {\n font-size: calc(1.375rem + 1.5vw);\n}\n@media (min-width: 1200px) {\n h1, .h1 {\n font-size: 2.5rem;\n }\n}\n\nh2, .h2 {\n font-size: calc(1.325rem + 0.9vw);\n}\n@media (min-width: 1200px) {\n h2, .h2 {\n font-size: 2rem;\n }\n}\n\nh3, .h3 {\n font-size: calc(1.3rem + 0.6vw);\n}\n@media (min-width: 1200px) {\n h3, .h3 {\n font-size: 1.75rem;\n }\n}\n\nh4, .h4 {\n font-size: calc(1.275rem + 0.3vw);\n}\n@media (min-width: 1200px) {\n h4, .h4 {\n font-size: 1.5rem;\n }\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title] {\n text-decoration: underline dotted;\n cursor: help;\n text-decoration-skip-ink: none;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: 0.5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall, .small {\n font-size: 0.875em;\n}\n\nmark, .mark {\n padding: 0.1875em;\n color: var(--bs-highlight-color);\n background-color: var(--bs-highlight-bg);\n}\n\nsub,\nsup {\n position: relative;\n font-size: 0.75em;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\na {\n color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));\n text-decoration: underline;\n}\na:hover {\n --bs-link-color-rgb: var(--bs-link-hover-color-rgb);\n}\n\na:not([href]):not([class]), a:not([href]):not([class]):hover {\n color: inherit;\n text-decoration: none;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: var(--bs-font-monospace);\n font-size: 1em;\n}\n\npre {\n display: block;\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n font-size: 0.875em;\n}\npre code {\n font-size: inherit;\n color: inherit;\n word-break: normal;\n}\n\ncode {\n font-size: 0.875em;\n color: var(--bs-code-color);\n word-wrap: break-word;\n}\na > code {\n color: inherit;\n}\n\nkbd {\n padding: 0.1875rem 0.375rem;\n font-size: 0.875em;\n color: var(--bs-body-bg);\n background-color: var(--bs-body-color);\n border-radius: 0.25rem;\n}\nkbd kbd {\n padding: 0;\n font-size: 1em;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n color: var(--bs-secondary-color);\n text-align: left;\n}\n\nth {\n text-align: inherit;\n text-align: -webkit-match-parent;\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\nlabel {\n display: inline-block;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\n[role=button] {\n cursor: pointer;\n}\n\nselect {\n word-wrap: normal;\n}\nselect:disabled {\n opacity: 1;\n}\n\n[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {\n display: none !important;\n}\n\nbutton,\n[type=button],\n[type=reset],\n[type=submit] {\n -webkit-appearance: button;\n}\nbutton:not(:disabled),\n[type=button]:not(:disabled),\n[type=reset]:not(:disabled),\n[type=submit]:not(:disabled) {\n cursor: pointer;\n}\n\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ntextarea {\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n float: left;\n width: 100%;\n padding: 0;\n margin-bottom: 0.5rem;\n font-size: calc(1.275rem + 0.3vw);\n line-height: inherit;\n}\n@media (min-width: 1200px) {\n legend {\n font-size: 1.5rem;\n }\n}\nlegend + * {\n clear: left;\n}\n\n::-webkit-datetime-edit-fields-wrapper,\n::-webkit-datetime-edit-text,\n::-webkit-datetime-edit-minute,\n::-webkit-datetime-edit-hour-field,\n::-webkit-datetime-edit-day-field,\n::-webkit-datetime-edit-month-field,\n::-webkit-datetime-edit-year-field {\n padding: 0;\n}\n\n::-webkit-inner-spin-button {\n height: auto;\n}\n\n[type=search] {\n -webkit-appearance: textfield;\n outline-offset: -2px;\n}\n\n/* rtl:raw:\n[type=\"tel\"],\n[type=\"url\"],\n[type=\"email\"],\n[type=\"number\"] {\n direction: ltr;\n}\n*/\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n::file-selector-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\niframe {\n border: 0;\n}\n\nsummary {\n display: list-item;\n cursor: pointer;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: calc(1.625rem + 4.5vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-1 {\n font-size: 5rem;\n }\n}\n\n.display-2 {\n font-size: calc(1.575rem + 3.9vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-2 {\n font-size: 4.5rem;\n }\n}\n\n.display-3 {\n font-size: calc(1.525rem + 3.3vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-3 {\n font-size: 4rem;\n }\n}\n\n.display-4 {\n font-size: calc(1.475rem + 2.7vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-4 {\n font-size: 3.5rem;\n }\n}\n\n.display-5 {\n font-size: calc(1.425rem + 2.1vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-5 {\n font-size: 3rem;\n }\n}\n\n.display-6 {\n font-size: calc(1.375rem + 1.5vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-6 {\n font-size: 2.5rem;\n }\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n.list-inline-item:not(:last-child) {\n margin-right: 0.5rem;\n}\n\n.initialism {\n font-size: 0.875em;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n.blockquote > :last-child {\n margin-bottom: 0;\n}\n\n.blockquote-footer {\n margin-top: -1rem;\n margin-bottom: 1rem;\n font-size: 0.875em;\n color: #6c757d;\n}\n.blockquote-footer::before {\n content: \"— \";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: var(--bs-body-bg);\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 0.875em;\n color: var(--bs-secondary-color);\n}\n\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n:root {\n --bs-breakpoint-xs: 0;\n --bs-breakpoint-sm: 576px;\n --bs-breakpoint-md: 768px;\n --bs-breakpoint-lg: 992px;\n --bs-breakpoint-xl: 1200px;\n --bs-breakpoint-xxl: 1400px;\n}\n\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-left: 8.33333333%;\n}\n\n.offset-2 {\n margin-left: 16.66666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.33333333%;\n}\n\n.offset-5 {\n margin-left: 41.66666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.33333333%;\n}\n\n.offset-8 {\n margin-left: 66.66666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.33333333%;\n}\n\n.offset-11 {\n margin-left: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.33333333%;\n }\n .offset-sm-2 {\n margin-left: 16.66666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.33333333%;\n }\n .offset-sm-5 {\n margin-left: 41.66666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.33333333%;\n }\n .offset-sm-8 {\n margin-left: 66.66666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.33333333%;\n }\n .offset-sm-11 {\n margin-left: 91.66666667%;\n }\n .g-sm-0,\n .gx-sm-0 {\n --bs-gutter-x: 0;\n }\n .g-sm-0,\n .gy-sm-0 {\n --bs-gutter-y: 0;\n }\n .g-sm-1,\n .gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-sm-1,\n .gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-sm-2,\n .gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-sm-2,\n .gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-sm-3,\n .gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n .g-sm-3,\n .gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n .g-sm-4,\n .gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-sm-4,\n .gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-sm-5,\n .gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n .g-sm-5,\n .gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.33333333%;\n }\n .offset-md-2 {\n margin-left: 16.66666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.33333333%;\n }\n .offset-md-5 {\n margin-left: 41.66666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.33333333%;\n }\n .offset-md-8 {\n margin-left: 66.66666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.33333333%;\n }\n .offset-md-11 {\n margin-left: 91.66666667%;\n }\n .g-md-0,\n .gx-md-0 {\n --bs-gutter-x: 0;\n }\n .g-md-0,\n .gy-md-0 {\n --bs-gutter-y: 0;\n }\n .g-md-1,\n .gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-md-1,\n .gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-md-2,\n .gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-md-2,\n .gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-md-3,\n .gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n .g-md-3,\n .gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n .g-md-4,\n .gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-md-4,\n .gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-md-5,\n .gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n .g-md-5,\n .gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.33333333%;\n }\n .offset-lg-2 {\n margin-left: 16.66666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.33333333%;\n }\n .offset-lg-5 {\n margin-left: 41.66666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.33333333%;\n }\n .offset-lg-8 {\n margin-left: 66.66666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.33333333%;\n }\n .offset-lg-11 {\n margin-left: 91.66666667%;\n }\n .g-lg-0,\n .gx-lg-0 {\n --bs-gutter-x: 0;\n }\n .g-lg-0,\n .gy-lg-0 {\n --bs-gutter-y: 0;\n }\n .g-lg-1,\n .gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-lg-1,\n .gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-lg-2,\n .gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-lg-2,\n .gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-lg-3,\n .gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n .g-lg-3,\n .gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n .g-lg-4,\n .gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-lg-4,\n .gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-lg-5,\n .gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n .g-lg-5,\n .gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xl-11 {\n margin-left: 91.66666667%;\n }\n .g-xl-0,\n .gx-xl-0 {\n --bs-gutter-x: 0;\n }\n .g-xl-0,\n .gy-xl-0 {\n --bs-gutter-y: 0;\n }\n .g-xl-1,\n .gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xl-1,\n .gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xl-2,\n .gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xl-2,\n .gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xl-3,\n .gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xl-3,\n .gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xl-4,\n .gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xl-4,\n .gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xl-5,\n .gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xl-5,\n .gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xxl-0 {\n margin-left: 0;\n }\n .offset-xxl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xxl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xxl-3 {\n margin-left: 25%;\n }\n .offset-xxl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xxl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xxl-6 {\n margin-left: 50%;\n }\n .offset-xxl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xxl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xxl-9 {\n margin-left: 75%;\n }\n .offset-xxl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xxl-11 {\n margin-left: 91.66666667%;\n }\n .g-xxl-0,\n .gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n .g-xxl-0,\n .gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n .g-xxl-1,\n .gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xxl-1,\n .gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xxl-2,\n .gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xxl-2,\n .gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xxl-3,\n .gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xxl-3,\n .gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xxl-4,\n .gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xxl-4,\n .gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xxl-5,\n .gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xxl-5,\n .gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.table {\n --bs-table-color-type: initial;\n --bs-table-bg-type: initial;\n --bs-table-color-state: initial;\n --bs-table-bg-state: initial;\n --bs-table-color: var(--bs-emphasis-color);\n --bs-table-bg: var(--bs-body-bg);\n --bs-table-border-color: var(--bs-border-color);\n --bs-table-accent-bg: transparent;\n --bs-table-striped-color: var(--bs-emphasis-color);\n --bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05);\n --bs-table-active-color: var(--bs-emphasis-color);\n --bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1);\n --bs-table-hover-color: var(--bs-emphasis-color);\n --bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075);\n width: 100%;\n margin-bottom: 1rem;\n vertical-align: top;\n border-color: var(--bs-table-border-color);\n}\n.table > :not(caption) > * > * {\n padding: 0.5rem 0.5rem;\n color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));\n background-color: var(--bs-table-bg);\n border-bottom-width: var(--bs-border-width);\n box-shadow: inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)));\n}\n.table > tbody {\n vertical-align: inherit;\n}\n.table > thead {\n vertical-align: bottom;\n}\n\n.table-group-divider {\n border-top: calc(var(--bs-border-width) * 2) solid currentcolor;\n}\n\n.caption-top {\n caption-side: top;\n}\n\n.table-sm > :not(caption) > * > * {\n padding: 0.25rem 0.25rem;\n}\n\n.table-bordered > :not(caption) > * {\n border-width: var(--bs-border-width) 0;\n}\n.table-bordered > :not(caption) > * > * {\n border-width: 0 var(--bs-border-width);\n}\n\n.table-borderless > :not(caption) > * > * {\n border-bottom-width: 0;\n}\n.table-borderless > :not(:first-child) {\n border-top-width: 0;\n}\n\n.table-striped > tbody > tr:nth-of-type(odd) > * {\n --bs-table-color-type: var(--bs-table-striped-color);\n --bs-table-bg-type: var(--bs-table-striped-bg);\n}\n\n.table-striped-columns > :not(caption) > tr > :nth-child(even) {\n --bs-table-color-type: var(--bs-table-striped-color);\n --bs-table-bg-type: var(--bs-table-striped-bg);\n}\n\n.table-active {\n --bs-table-color-state: var(--bs-table-active-color);\n --bs-table-bg-state: var(--bs-table-active-bg);\n}\n\n.table-hover > tbody > tr:hover > * {\n --bs-table-color-state: var(--bs-table-hover-color);\n --bs-table-bg-state: var(--bs-table-hover-bg);\n}\n\n.table-primary {\n --bs-table-color: #000;\n --bs-table-bg: #cfe2ff;\n --bs-table-border-color: #a6b5cc;\n --bs-table-striped-bg: #c5d7f2;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #bacbe6;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #bfd1ec;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-secondary {\n --bs-table-color: #000;\n --bs-table-bg: #e2e3e5;\n --bs-table-border-color: #b5b6b7;\n --bs-table-striped-bg: #d7d8da;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #cbccce;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #d1d2d4;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-success {\n --bs-table-color: #000;\n --bs-table-bg: #d1e7dd;\n --bs-table-border-color: #a7b9b1;\n --bs-table-striped-bg: #c7dbd2;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #bcd0c7;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #c1d6cc;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-info {\n --bs-table-color: #000;\n --bs-table-bg: #cff4fc;\n --bs-table-border-color: #a6c3ca;\n --bs-table-striped-bg: #c5e8ef;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #badce3;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #bfe2e9;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-warning {\n --bs-table-color: #000;\n --bs-table-bg: #fff3cd;\n --bs-table-border-color: #ccc2a4;\n --bs-table-striped-bg: #f2e7c3;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #e6dbb9;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #ece1be;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-danger {\n --bs-table-color: #000;\n --bs-table-bg: #f8d7da;\n --bs-table-border-color: #c6acae;\n --bs-table-striped-bg: #eccccf;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #dfc2c4;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #e5c7ca;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-light {\n --bs-table-color: #000;\n --bs-table-bg: #f8f9fa;\n --bs-table-border-color: #c6c7c8;\n --bs-table-striped-bg: #ecedee;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #dfe0e1;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #e5e6e7;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-dark {\n --bs-table-color: #fff;\n --bs-table-bg: #212529;\n --bs-table-border-color: #4d5154;\n --bs-table-striped-bg: #2c3034;\n --bs-table-striped-color: #fff;\n --bs-table-active-bg: #373b3e;\n --bs-table-active-color: #fff;\n --bs-table-hover-bg: #323539;\n --bs-table-hover-color: #fff;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-responsive {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n@media (max-width: 575.98px) {\n .table-responsive-sm {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 767.98px) {\n .table-responsive-md {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 991.98px) {\n .table-responsive-lg {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 1199.98px) {\n .table-responsive-xl {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 1399.98px) {\n .table-responsive-xxl {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n.form-label {\n margin-bottom: 0.5rem;\n}\n\n.col-form-label {\n padding-top: calc(0.375rem + var(--bs-border-width));\n padding-bottom: calc(0.375rem + var(--bs-border-width));\n margin-bottom: 0;\n font-size: inherit;\n line-height: 1.5;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem + var(--bs-border-width));\n padding-bottom: calc(0.5rem + var(--bs-border-width));\n font-size: 1.25rem;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem + var(--bs-border-width));\n padding-bottom: calc(0.25rem + var(--bs-border-width));\n font-size: 0.875rem;\n}\n\n.form-text {\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: var(--bs-secondary-color);\n}\n\n.form-control {\n display: block;\n width: 100%;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: var(--bs-body-color);\n appearance: none;\n background-color: var(--bs-body-bg);\n background-clip: padding-box;\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control {\n transition: none;\n }\n}\n.form-control[type=file] {\n overflow: hidden;\n}\n.form-control[type=file]:not(:disabled):not([readonly]) {\n cursor: pointer;\n}\n.form-control:focus {\n color: var(--bs-body-color);\n background-color: var(--bs-body-bg);\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-control::-webkit-date-and-time-value {\n min-width: 85px;\n height: 1.5em;\n margin: 0;\n}\n.form-control::-webkit-datetime-edit {\n display: block;\n padding: 0;\n}\n.form-control::placeholder {\n color: var(--bs-secondary-color);\n opacity: 1;\n}\n.form-control:disabled {\n background-color: var(--bs-secondary-bg);\n opacity: 1;\n}\n.form-control::file-selector-button {\n padding: 0.375rem 0.75rem;\n margin: -0.375rem -0.75rem;\n margin-inline-end: 0.75rem;\n color: var(--bs-body-color);\n background-color: var(--bs-tertiary-bg);\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: var(--bs-border-width);\n border-radius: 0;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control::file-selector-button {\n transition: none;\n }\n}\n.form-control:hover:not(:disabled):not([readonly])::file-selector-button {\n background-color: var(--bs-secondary-bg);\n}\n\n.form-control-plaintext {\n display: block;\n width: 100%;\n padding: 0.375rem 0;\n margin-bottom: 0;\n line-height: 1.5;\n color: var(--bs-body-color);\n background-color: transparent;\n border: solid transparent;\n border-width: var(--bs-border-width) 0;\n}\n.form-control-plaintext:focus {\n outline: 0;\n}\n.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm {\n min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: var(--bs-border-radius-sm);\n}\n.form-control-sm::file-selector-button {\n padding: 0.25rem 0.5rem;\n margin: -0.25rem -0.5rem;\n margin-inline-end: 0.5rem;\n}\n\n.form-control-lg {\n min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: var(--bs-border-radius-lg);\n}\n.form-control-lg::file-selector-button {\n padding: 0.5rem 1rem;\n margin: -0.5rem -1rem;\n margin-inline-end: 1rem;\n}\n\ntextarea.form-control {\n min-height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));\n}\ntextarea.form-control-sm {\n min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));\n}\ntextarea.form-control-lg {\n min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));\n}\n\n.form-control-color {\n width: 3rem;\n height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));\n padding: 0.375rem;\n}\n.form-control-color:not(:disabled):not([readonly]) {\n cursor: pointer;\n}\n.form-control-color::-moz-color-swatch {\n border: 0 !important;\n border-radius: var(--bs-border-radius);\n}\n.form-control-color::-webkit-color-swatch {\n border: 0 !important;\n border-radius: var(--bs-border-radius);\n}\n.form-control-color.form-control-sm {\n height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));\n}\n.form-control-color.form-control-lg {\n height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));\n}\n\n.form-select {\n --bs-form-select-bg-img: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e\");\n display: block;\n width: 100%;\n padding: 0.375rem 2.25rem 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: var(--bs-body-color);\n appearance: none;\n background-color: var(--bs-body-bg);\n background-image: var(--bs-form-select-bg-img), var(--bs-form-select-bg-icon, none);\n background-repeat: no-repeat;\n background-position: right 0.75rem center;\n background-size: 16px 12px;\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-select {\n transition: none;\n }\n}\n.form-select:focus {\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-select[multiple], .form-select[size]:not([size=\"1\"]) {\n padding-right: 0.75rem;\n background-image: none;\n}\n.form-select:disabled {\n background-color: var(--bs-secondary-bg);\n}\n.form-select:-moz-focusring {\n color: transparent;\n text-shadow: 0 0 0 var(--bs-body-color);\n}\n\n.form-select-sm {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n padding-left: 0.5rem;\n font-size: 0.875rem;\n border-radius: var(--bs-border-radius-sm);\n}\n\n.form-select-lg {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n padding-left: 1rem;\n font-size: 1.25rem;\n border-radius: var(--bs-border-radius-lg);\n}\n\n[data-bs-theme=dark] .form-select {\n --bs-form-select-bg-img: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e\");\n}\n\n.form-check {\n display: block;\n min-height: 1.5rem;\n padding-left: 1.5em;\n margin-bottom: 0.125rem;\n}\n.form-check .form-check-input {\n float: left;\n margin-left: -1.5em;\n}\n\n.form-check-reverse {\n padding-right: 1.5em;\n padding-left: 0;\n text-align: right;\n}\n.form-check-reverse .form-check-input {\n float: right;\n margin-right: -1.5em;\n margin-left: 0;\n}\n\n.form-check-input {\n --bs-form-check-bg: var(--bs-body-bg);\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n margin-top: 0.25em;\n vertical-align: top;\n appearance: none;\n background-color: var(--bs-form-check-bg);\n background-image: var(--bs-form-check-bg-image);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border: var(--bs-border-width) solid var(--bs-border-color);\n print-color-adjust: exact;\n}\n.form-check-input[type=checkbox] {\n border-radius: 0.25em;\n}\n.form-check-input[type=radio] {\n border-radius: 50%;\n}\n.form-check-input:active {\n filter: brightness(90%);\n}\n.form-check-input:focus {\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-check-input:checked {\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.form-check-input:checked[type=checkbox] {\n --bs-form-check-bg-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e\");\n}\n.form-check-input:checked[type=radio] {\n --bs-form-check-bg-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e\");\n}\n.form-check-input[type=checkbox]:indeterminate {\n background-color: #0d6efd;\n border-color: #0d6efd;\n --bs-form-check-bg-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e\");\n}\n.form-check-input:disabled {\n pointer-events: none;\n filter: none;\n opacity: 0.5;\n}\n.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label {\n cursor: default;\n opacity: 0.5;\n}\n\n.form-switch {\n padding-left: 2.5em;\n}\n.form-switch .form-check-input {\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e\");\n width: 2em;\n margin-left: -2.5em;\n background-image: var(--bs-form-switch-bg);\n background-position: left center;\n border-radius: 2em;\n transition: background-position 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-switch .form-check-input {\n transition: none;\n }\n}\n.form-switch .form-check-input:focus {\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e\");\n}\n.form-switch .form-check-input:checked {\n background-position: right center;\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\");\n}\n.form-switch.form-check-reverse {\n padding-right: 2.5em;\n padding-left: 0;\n}\n.form-switch.form-check-reverse .form-check-input {\n margin-right: -2.5em;\n margin-left: 0;\n}\n\n.form-check-inline {\n display: inline-block;\n margin-right: 1rem;\n}\n\n.btn-check {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.btn-check[disabled] + .btn, .btn-check:disabled + .btn {\n pointer-events: none;\n filter: none;\n opacity: 0.65;\n}\n\n[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus) {\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e\");\n}\n\n.form-range {\n width: 100%;\n height: 1.5rem;\n padding: 0;\n appearance: none;\n background-color: transparent;\n}\n.form-range:focus {\n outline: 0;\n}\n.form-range:focus::-webkit-slider-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-range:focus::-moz-range-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-range::-moz-focus-outer {\n border: 0;\n}\n.form-range::-webkit-slider-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: -0.25rem;\n appearance: none;\n background-color: #0d6efd;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-range::-webkit-slider-thumb {\n transition: none;\n }\n}\n.form-range::-webkit-slider-thumb:active {\n background-color: #b6d4fe;\n}\n.form-range::-webkit-slider-runnable-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: var(--bs-secondary-bg);\n border-color: transparent;\n border-radius: 1rem;\n}\n.form-range::-moz-range-thumb {\n width: 1rem;\n height: 1rem;\n appearance: none;\n background-color: #0d6efd;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-range::-moz-range-thumb {\n transition: none;\n }\n}\n.form-range::-moz-range-thumb:active {\n background-color: #b6d4fe;\n}\n.form-range::-moz-range-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: var(--bs-secondary-bg);\n border-color: transparent;\n border-radius: 1rem;\n}\n.form-range:disabled {\n pointer-events: none;\n}\n.form-range:disabled::-webkit-slider-thumb {\n background-color: var(--bs-secondary-color);\n}\n.form-range:disabled::-moz-range-thumb {\n background-color: var(--bs-secondary-color);\n}\n\n.form-floating {\n position: relative;\n}\n.form-floating > .form-control,\n.form-floating > .form-control-plaintext,\n.form-floating > .form-select {\n height: calc(3.5rem + calc(var(--bs-border-width) * 2));\n min-height: calc(3.5rem + calc(var(--bs-border-width) * 2));\n line-height: 1.25;\n}\n.form-floating > label {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n height: 100%;\n padding: 1rem 0.75rem;\n overflow: hidden;\n text-align: start;\n text-overflow: ellipsis;\n white-space: nowrap;\n pointer-events: none;\n border: var(--bs-border-width) solid transparent;\n transform-origin: 0 0;\n transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-floating > label {\n transition: none;\n }\n}\n.form-floating > .form-control,\n.form-floating > .form-control-plaintext {\n padding: 1rem 0.75rem;\n}\n.form-floating > .form-control::placeholder,\n.form-floating > .form-control-plaintext::placeholder {\n color: transparent;\n}\n.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown),\n.form-floating > .form-control-plaintext:focus,\n.form-floating > .form-control-plaintext:not(:placeholder-shown) {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:-webkit-autofill,\n.form-floating > .form-control-plaintext:-webkit-autofill {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-select {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:focus ~ label,\n.form-floating > .form-control:not(:placeholder-shown) ~ label,\n.form-floating > .form-control-plaintext ~ label,\n.form-floating > .form-select ~ label {\n color: rgba(var(--bs-body-color-rgb), 0.65);\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control:focus ~ label::after,\n.form-floating > .form-control:not(:placeholder-shown) ~ label::after,\n.form-floating > .form-control-plaintext ~ label::after,\n.form-floating > .form-select ~ label::after {\n position: absolute;\n inset: 1rem 0.375rem;\n z-index: -1;\n height: 1.5em;\n content: \"\";\n background-color: var(--bs-body-bg);\n border-radius: var(--bs-border-radius);\n}\n.form-floating > .form-control:-webkit-autofill ~ label {\n color: rgba(var(--bs-body-color-rgb), 0.65);\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control-plaintext ~ label {\n border-width: var(--bs-border-width) 0;\n}\n.form-floating > :disabled ~ label,\n.form-floating > .form-control:disabled ~ label {\n color: #6c757d;\n}\n.form-floating > :disabled ~ label::after,\n.form-floating > .form-control:disabled ~ label::after {\n background-color: var(--bs-secondary-bg);\n}\n\n.input-group {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n width: 100%;\n}\n.input-group > .form-control,\n.input-group > .form-select,\n.input-group > .form-floating {\n position: relative;\n flex: 1 1 auto;\n width: 1%;\n min-width: 0;\n}\n.input-group > .form-control:focus,\n.input-group > .form-select:focus,\n.input-group > .form-floating:focus-within {\n z-index: 5;\n}\n.input-group .btn {\n position: relative;\n z-index: 2;\n}\n.input-group .btn:focus {\n z-index: 5;\n}\n\n.input-group-text {\n display: flex;\n align-items: center;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: var(--bs-body-color);\n text-align: center;\n white-space: nowrap;\n background-color: var(--bs-tertiary-bg);\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .form-select,\n.input-group-lg > .input-group-text,\n.input-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: var(--bs-border-radius-lg);\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .form-select,\n.input-group-sm > .input-group-text,\n.input-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: var(--bs-border-radius-sm);\n}\n\n.input-group-lg > .form-select,\n.input-group-sm > .form-select {\n padding-right: 3rem;\n}\n\n.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\n.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3),\n.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control,\n.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\n.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4),\n.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control,\n.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {\n margin-left: calc(var(--bs-border-width) * -1);\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group > .form-floating:not(:first-child) > .form-control,\n.input-group > .form-floating:not(:first-child) > .form-select {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.valid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: var(--bs-form-valid-color);\n}\n\n.valid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: 0.1rem;\n font-size: 0.875rem;\n color: #fff;\n background-color: var(--bs-success);\n border-radius: var(--bs-border-radius);\n}\n\n.was-validated :valid ~ .valid-feedback,\n.was-validated :valid ~ .valid-tooltip,\n.is-valid ~ .valid-feedback,\n.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid {\n border-color: var(--bs-form-valid-border-color);\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right calc(0.375em + 0.1875rem) center;\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus {\n border-color: var(--bs-form-valid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);\n}\n\n.was-validated textarea.form-control:valid, textarea.form-control.is-valid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .form-select:valid, .form-select.is-valid {\n border-color: var(--bs-form-valid-border-color);\n}\n.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size=\"1\"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size=\"1\"] {\n --bs-form-select-bg-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n padding-right: 4.125rem;\n background-position: right 0.75rem center, center right 2.25rem;\n background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-select:valid:focus, .form-select.is-valid:focus {\n border-color: var(--bs-form-valid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);\n}\n\n.was-validated .form-control-color:valid, .form-control-color.is-valid {\n width: calc(3rem + calc(1.5em + 0.75rem));\n}\n\n.was-validated .form-check-input:valid, .form-check-input.is-valid {\n border-color: var(--bs-form-valid-border-color);\n}\n.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {\n background-color: var(--bs-form-valid-color);\n}\n.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus {\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);\n}\n.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {\n color: var(--bs-form-valid-color);\n}\n\n.form-check-inline .form-check-input ~ .valid-feedback {\n margin-left: 0.5em;\n}\n\n.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid,\n.was-validated .input-group > .form-select:not(:focus):valid,\n.input-group > .form-select:not(:focus).is-valid,\n.was-validated .input-group > .form-floating:not(:focus-within):valid,\n.input-group > .form-floating:not(:focus-within).is-valid {\n z-index: 3;\n}\n\n.invalid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: var(--bs-form-invalid-color);\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: 0.1rem;\n font-size: 0.875rem;\n color: #fff;\n background-color: var(--bs-danger);\n border-radius: var(--bs-border-radius);\n}\n\n.was-validated :invalid ~ .invalid-feedback,\n.was-validated :invalid ~ .invalid-tooltip,\n.is-invalid ~ .invalid-feedback,\n.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid {\n border-color: var(--bs-form-invalid-border-color);\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right calc(0.375em + 0.1875rem) center;\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {\n border-color: var(--bs-form-invalid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);\n}\n\n.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .form-select:invalid, .form-select.is-invalid {\n border-color: var(--bs-form-invalid-border-color);\n}\n.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size=\"1\"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size=\"1\"] {\n --bs-form-select-bg-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");\n padding-right: 4.125rem;\n background-position: right 0.75rem center, center right 2.25rem;\n background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus {\n border-color: var(--bs-form-invalid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);\n}\n\n.was-validated .form-control-color:invalid, .form-control-color.is-invalid {\n width: calc(3rem + calc(1.5em + 0.75rem));\n}\n\n.was-validated .form-check-input:invalid, .form-check-input.is-invalid {\n border-color: var(--bs-form-invalid-border-color);\n}\n.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {\n background-color: var(--bs-form-invalid-color);\n}\n.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus {\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);\n}\n.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {\n color: var(--bs-form-invalid-color);\n}\n\n.form-check-inline .form-check-input ~ .invalid-feedback {\n margin-left: 0.5em;\n}\n\n.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid,\n.was-validated .input-group > .form-select:not(:focus):invalid,\n.input-group > .form-select:not(:focus).is-invalid,\n.was-validated .input-group > .form-floating:not(:focus-within):invalid,\n.input-group > .form-floating:not(:focus-within).is-invalid {\n z-index: 4;\n}\n\n.btn {\n --bs-btn-padding-x: 0.75rem;\n --bs-btn-padding-y: 0.375rem;\n --bs-btn-font-family: ;\n --bs-btn-font-size: 1rem;\n --bs-btn-font-weight: 400;\n --bs-btn-line-height: 1.5;\n --bs-btn-color: var(--bs-body-color);\n --bs-btn-bg: transparent;\n --bs-btn-border-width: var(--bs-border-width);\n --bs-btn-border-color: transparent;\n --bs-btn-border-radius: var(--bs-border-radius);\n --bs-btn-hover-border-color: transparent;\n --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n --bs-btn-disabled-opacity: 0.65;\n --bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);\n display: inline-block;\n padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x);\n font-family: var(--bs-btn-font-family);\n font-size: var(--bs-btn-font-size);\n font-weight: var(--bs-btn-font-weight);\n line-height: var(--bs-btn-line-height);\n color: var(--bs-btn-color);\n text-align: center;\n text-decoration: none;\n vertical-align: middle;\n cursor: pointer;\n user-select: none;\n border: var(--bs-btn-border-width) solid var(--bs-btn-border-color);\n border-radius: var(--bs-btn-border-radius);\n background-color: var(--bs-btn-bg);\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .btn {\n transition: none;\n }\n}\n.btn:hover {\n color: var(--bs-btn-hover-color);\n background-color: var(--bs-btn-hover-bg);\n border-color: var(--bs-btn-hover-border-color);\n}\n.btn-check + .btn:hover {\n color: var(--bs-btn-color);\n background-color: var(--bs-btn-bg);\n border-color: var(--bs-btn-border-color);\n}\n.btn:focus-visible {\n color: var(--bs-btn-hover-color);\n background-color: var(--bs-btn-hover-bg);\n border-color: var(--bs-btn-hover-border-color);\n outline: 0;\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn-check:focus-visible + .btn {\n border-color: var(--bs-btn-hover-border-color);\n outline: 0;\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, .btn.active, .btn.show {\n color: var(--bs-btn-active-color);\n background-color: var(--bs-btn-active-bg);\n border-color: var(--bs-btn-active-border-color);\n}\n.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible {\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn-check:checked:focus-visible + .btn {\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn:disabled, .btn.disabled, fieldset:disabled .btn {\n color: var(--bs-btn-disabled-color);\n pointer-events: none;\n background-color: var(--bs-btn-disabled-bg);\n border-color: var(--bs-btn-disabled-border-color);\n opacity: var(--bs-btn-disabled-opacity);\n}\n\n.btn-primary {\n --bs-btn-color: #fff;\n --bs-btn-bg: #0d6efd;\n --bs-btn-border-color: #0d6efd;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #0b5ed7;\n --bs-btn-hover-border-color: #0a58ca;\n --bs-btn-focus-shadow-rgb: 49, 132, 253;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #0a58ca;\n --bs-btn-active-border-color: #0a53be;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #0d6efd;\n --bs-btn-disabled-border-color: #0d6efd;\n}\n\n.btn-secondary {\n --bs-btn-color: #fff;\n --bs-btn-bg: #6c757d;\n --bs-btn-border-color: #6c757d;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #5c636a;\n --bs-btn-hover-border-color: #565e64;\n --bs-btn-focus-shadow-rgb: 130, 138, 145;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #565e64;\n --bs-btn-active-border-color: #51585e;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #6c757d;\n --bs-btn-disabled-border-color: #6c757d;\n}\n\n.btn-success {\n --bs-btn-color: #fff;\n --bs-btn-bg: #198754;\n --bs-btn-border-color: #198754;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #157347;\n --bs-btn-hover-border-color: #146c43;\n --bs-btn-focus-shadow-rgb: 60, 153, 110;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #146c43;\n --bs-btn-active-border-color: #13653f;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #198754;\n --bs-btn-disabled-border-color: #198754;\n}\n\n.btn-info {\n --bs-btn-color: #000;\n --bs-btn-bg: #0dcaf0;\n --bs-btn-border-color: #0dcaf0;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #31d2f2;\n --bs-btn-hover-border-color: #25cff2;\n --bs-btn-focus-shadow-rgb: 11, 172, 204;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #3dd5f3;\n --bs-btn-active-border-color: #25cff2;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #000;\n --bs-btn-disabled-bg: #0dcaf0;\n --bs-btn-disabled-border-color: #0dcaf0;\n}\n\n.btn-warning {\n --bs-btn-color: #000;\n --bs-btn-bg: #ffc107;\n --bs-btn-border-color: #ffc107;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #ffca2c;\n --bs-btn-hover-border-color: #ffc720;\n --bs-btn-focus-shadow-rgb: 217, 164, 6;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #ffcd39;\n --bs-btn-active-border-color: #ffc720;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #000;\n --bs-btn-disabled-bg: #ffc107;\n --bs-btn-disabled-border-color: #ffc107;\n}\n\n.btn-danger {\n --bs-btn-color: #fff;\n --bs-btn-bg: #dc3545;\n --bs-btn-border-color: #dc3545;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #bb2d3b;\n --bs-btn-hover-border-color: #b02a37;\n --bs-btn-focus-shadow-rgb: 225, 83, 97;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #b02a37;\n --bs-btn-active-border-color: #a52834;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #dc3545;\n --bs-btn-disabled-border-color: #dc3545;\n}\n\n.btn-light {\n --bs-btn-color: #000;\n --bs-btn-bg: #f8f9fa;\n --bs-btn-border-color: #f8f9fa;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #d3d4d5;\n --bs-btn-hover-border-color: #c6c7c8;\n --bs-btn-focus-shadow-rgb: 211, 212, 213;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #c6c7c8;\n --bs-btn-active-border-color: #babbbc;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #000;\n --bs-btn-disabled-bg: #f8f9fa;\n --bs-btn-disabled-border-color: #f8f9fa;\n}\n\n.btn-dark {\n --bs-btn-color: #fff;\n --bs-btn-bg: #212529;\n --bs-btn-border-color: #212529;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #424649;\n --bs-btn-hover-border-color: #373b3e;\n --bs-btn-focus-shadow-rgb: 66, 70, 73;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #4d5154;\n --bs-btn-active-border-color: #373b3e;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #212529;\n --bs-btn-disabled-border-color: #212529;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #0d6efd;\n --bs-btn-border-color: #0d6efd;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #0d6efd;\n --bs-btn-hover-border-color: #0d6efd;\n --bs-btn-focus-shadow-rgb: 13, 110, 253;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #0d6efd;\n --bs-btn-active-border-color: #0d6efd;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #0d6efd;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #0d6efd;\n --bs-gradient: none;\n}\n\n.btn-outline-secondary {\n --bs-btn-color: #6c757d;\n --bs-btn-border-color: #6c757d;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #6c757d;\n --bs-btn-hover-border-color: #6c757d;\n --bs-btn-focus-shadow-rgb: 108, 117, 125;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #6c757d;\n --bs-btn-active-border-color: #6c757d;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #6c757d;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #6c757d;\n --bs-gradient: none;\n}\n\n.btn-outline-success {\n --bs-btn-color: #198754;\n --bs-btn-border-color: #198754;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #198754;\n --bs-btn-hover-border-color: #198754;\n --bs-btn-focus-shadow-rgb: 25, 135, 84;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #198754;\n --bs-btn-active-border-color: #198754;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #198754;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #198754;\n --bs-gradient: none;\n}\n\n.btn-outline-info {\n --bs-btn-color: #0dcaf0;\n --bs-btn-border-color: #0dcaf0;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #0dcaf0;\n --bs-btn-hover-border-color: #0dcaf0;\n --bs-btn-focus-shadow-rgb: 13, 202, 240;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #0dcaf0;\n --bs-btn-active-border-color: #0dcaf0;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #0dcaf0;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #0dcaf0;\n --bs-gradient: none;\n}\n\n.btn-outline-warning {\n --bs-btn-color: #ffc107;\n --bs-btn-border-color: #ffc107;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #ffc107;\n --bs-btn-hover-border-color: #ffc107;\n --bs-btn-focus-shadow-rgb: 255, 193, 7;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #ffc107;\n --bs-btn-active-border-color: #ffc107;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #ffc107;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #ffc107;\n --bs-gradient: none;\n}\n\n.btn-outline-danger {\n --bs-btn-color: #dc3545;\n --bs-btn-border-color: #dc3545;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #dc3545;\n --bs-btn-hover-border-color: #dc3545;\n --bs-btn-focus-shadow-rgb: 220, 53, 69;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #dc3545;\n --bs-btn-active-border-color: #dc3545;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #dc3545;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #dc3545;\n --bs-gradient: none;\n}\n\n.btn-outline-light {\n --bs-btn-color: #f8f9fa;\n --bs-btn-border-color: #f8f9fa;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #f8f9fa;\n --bs-btn-hover-border-color: #f8f9fa;\n --bs-btn-focus-shadow-rgb: 248, 249, 250;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #f8f9fa;\n --bs-btn-active-border-color: #f8f9fa;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #f8f9fa;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #f8f9fa;\n --bs-gradient: none;\n}\n\n.btn-outline-dark {\n --bs-btn-color: #212529;\n --bs-btn-border-color: #212529;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #212529;\n --bs-btn-hover-border-color: #212529;\n --bs-btn-focus-shadow-rgb: 33, 37, 41;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #212529;\n --bs-btn-active-border-color: #212529;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #212529;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #212529;\n --bs-gradient: none;\n}\n\n.btn-link {\n --bs-btn-font-weight: 400;\n --bs-btn-color: var(--bs-link-color);\n --bs-btn-bg: transparent;\n --bs-btn-border-color: transparent;\n --bs-btn-hover-color: var(--bs-link-hover-color);\n --bs-btn-hover-border-color: transparent;\n --bs-btn-active-color: var(--bs-link-hover-color);\n --bs-btn-active-border-color: transparent;\n --bs-btn-disabled-color: #6c757d;\n --bs-btn-disabled-border-color: transparent;\n --bs-btn-box-shadow: 0 0 0 #000;\n --bs-btn-focus-shadow-rgb: 49, 132, 253;\n text-decoration: underline;\n}\n.btn-link:focus-visible {\n color: var(--bs-btn-color);\n}\n.btn-link:hover {\n color: var(--bs-btn-hover-color);\n}\n\n.btn-lg, .btn-group-lg > .btn {\n --bs-btn-padding-y: 0.5rem;\n --bs-btn-padding-x: 1rem;\n --bs-btn-font-size: 1.25rem;\n --bs-btn-border-radius: var(--bs-border-radius-lg);\n}\n\n.btn-sm, .btn-group-sm > .btn {\n --bs-btn-padding-y: 0.25rem;\n --bs-btn-padding-x: 0.5rem;\n --bs-btn-font-size: 0.875rem;\n --bs-btn-border-radius: var(--bs-border-radius-sm);\n}\n\n.fade {\n transition: opacity 0.15s linear;\n}\n@media (prefers-reduced-motion: reduce) {\n .fade {\n transition: none;\n }\n}\n.fade:not(.show) {\n opacity: 0;\n}\n\n.collapse:not(.show) {\n display: none;\n}\n\n.collapsing {\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .collapsing {\n transition: none;\n }\n}\n.collapsing.collapse-horizontal {\n width: 0;\n height: auto;\n transition: width 0.35s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .collapsing.collapse-horizontal {\n transition: none;\n }\n}\n\n.dropup,\n.dropend,\n.dropdown,\n.dropstart,\n.dropup-center,\n.dropdown-center {\n position: relative;\n}\n\n.dropdown-toggle {\n white-space: nowrap;\n}\n.dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-bottom: 0;\n border-left: 0.3em solid transparent;\n}\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropdown-menu {\n --bs-dropdown-zindex: 1000;\n --bs-dropdown-min-width: 10rem;\n --bs-dropdown-padding-x: 0;\n --bs-dropdown-padding-y: 0.5rem;\n --bs-dropdown-spacer: 0.125rem;\n --bs-dropdown-font-size: 1rem;\n --bs-dropdown-color: var(--bs-body-color);\n --bs-dropdown-bg: var(--bs-body-bg);\n --bs-dropdown-border-color: var(--bs-border-color-translucent);\n --bs-dropdown-border-radius: var(--bs-border-radius);\n --bs-dropdown-border-width: var(--bs-border-width);\n --bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));\n --bs-dropdown-divider-bg: var(--bs-border-color-translucent);\n --bs-dropdown-divider-margin-y: 0.5rem;\n --bs-dropdown-box-shadow: var(--bs-box-shadow);\n --bs-dropdown-link-color: var(--bs-body-color);\n --bs-dropdown-link-hover-color: var(--bs-body-color);\n --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);\n --bs-dropdown-link-active-color: #fff;\n --bs-dropdown-link-active-bg: #0d6efd;\n --bs-dropdown-link-disabled-color: var(--bs-tertiary-color);\n --bs-dropdown-item-padding-x: 1rem;\n --bs-dropdown-item-padding-y: 0.25rem;\n --bs-dropdown-header-color: #6c757d;\n --bs-dropdown-header-padding-x: 1rem;\n --bs-dropdown-header-padding-y: 0.5rem;\n position: absolute;\n z-index: var(--bs-dropdown-zindex);\n display: none;\n min-width: var(--bs-dropdown-min-width);\n padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);\n margin: 0;\n font-size: var(--bs-dropdown-font-size);\n color: var(--bs-dropdown-color);\n text-align: left;\n list-style: none;\n background-color: var(--bs-dropdown-bg);\n background-clip: padding-box;\n border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);\n border-radius: var(--bs-dropdown-border-radius);\n}\n.dropdown-menu[data-bs-popper] {\n top: 100%;\n left: 0;\n margin-top: var(--bs-dropdown-spacer);\n}\n\n.dropdown-menu-start {\n --bs-position: start;\n}\n.dropdown-menu-start[data-bs-popper] {\n right: auto;\n left: 0;\n}\n\n.dropdown-menu-end {\n --bs-position: end;\n}\n.dropdown-menu-end[data-bs-popper] {\n right: 0;\n left: auto;\n}\n\n@media (min-width: 576px) {\n .dropdown-menu-sm-start {\n --bs-position: start;\n }\n .dropdown-menu-sm-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-sm-end {\n --bs-position: end;\n }\n .dropdown-menu-sm-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 768px) {\n .dropdown-menu-md-start {\n --bs-position: start;\n }\n .dropdown-menu-md-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-md-end {\n --bs-position: end;\n }\n .dropdown-menu-md-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 992px) {\n .dropdown-menu-lg-start {\n --bs-position: start;\n }\n .dropdown-menu-lg-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-lg-end {\n --bs-position: end;\n }\n .dropdown-menu-lg-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 1200px) {\n .dropdown-menu-xl-start {\n --bs-position: start;\n }\n .dropdown-menu-xl-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-xl-end {\n --bs-position: end;\n }\n .dropdown-menu-xl-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 1400px) {\n .dropdown-menu-xxl-start {\n --bs-position: start;\n }\n .dropdown-menu-xxl-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-xxl-end {\n --bs-position: end;\n }\n .dropdown-menu-xxl-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n.dropup .dropdown-menu[data-bs-popper] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: var(--bs-dropdown-spacer);\n}\n.dropup .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0;\n border-right: 0.3em solid transparent;\n border-bottom: 0.3em solid;\n border-left: 0.3em solid transparent;\n}\n.dropup .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropend .dropdown-menu[data-bs-popper] {\n top: 0;\n right: auto;\n left: 100%;\n margin-top: 0;\n margin-left: var(--bs-dropdown-spacer);\n}\n.dropend .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0;\n border-bottom: 0.3em solid transparent;\n border-left: 0.3em solid;\n}\n.dropend .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n.dropend .dropdown-toggle::after {\n vertical-align: 0;\n}\n\n.dropstart .dropdown-menu[data-bs-popper] {\n top: 0;\n right: 100%;\n left: auto;\n margin-top: 0;\n margin-right: var(--bs-dropdown-spacer);\n}\n.dropstart .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n}\n.dropstart .dropdown-toggle::after {\n display: none;\n}\n.dropstart .dropdown-toggle::before {\n display: inline-block;\n margin-right: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0.3em solid;\n border-bottom: 0.3em solid transparent;\n}\n.dropstart .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n.dropstart .dropdown-toggle::before {\n vertical-align: 0;\n}\n\n.dropdown-divider {\n height: 0;\n margin: var(--bs-dropdown-divider-margin-y) 0;\n overflow: hidden;\n border-top: 1px solid var(--bs-dropdown-divider-bg);\n opacity: 1;\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);\n clear: both;\n font-weight: 400;\n color: var(--bs-dropdown-link-color);\n text-align: inherit;\n text-decoration: none;\n white-space: nowrap;\n background-color: transparent;\n border: 0;\n border-radius: var(--bs-dropdown-item-border-radius, 0);\n}\n.dropdown-item:hover, .dropdown-item:focus {\n color: var(--bs-dropdown-link-hover-color);\n background-color: var(--bs-dropdown-link-hover-bg);\n}\n.dropdown-item.active, .dropdown-item:active {\n color: var(--bs-dropdown-link-active-color);\n text-decoration: none;\n background-color: var(--bs-dropdown-link-active-bg);\n}\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: var(--bs-dropdown-link-disabled-color);\n pointer-events: none;\n background-color: transparent;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);\n margin-bottom: 0;\n font-size: 0.875rem;\n color: var(--bs-dropdown-header-color);\n white-space: nowrap;\n}\n\n.dropdown-item-text {\n display: block;\n padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);\n color: var(--bs-dropdown-link-color);\n}\n\n.dropdown-menu-dark {\n --bs-dropdown-color: #dee2e6;\n --bs-dropdown-bg: #343a40;\n --bs-dropdown-border-color: var(--bs-border-color-translucent);\n --bs-dropdown-box-shadow: ;\n --bs-dropdown-link-color: #dee2e6;\n --bs-dropdown-link-hover-color: #fff;\n --bs-dropdown-divider-bg: var(--bs-border-color-translucent);\n --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);\n --bs-dropdown-link-active-color: #fff;\n --bs-dropdown-link-active-bg: #0d6efd;\n --bs-dropdown-link-disabled-color: #adb5bd;\n --bs-dropdown-header-color: #adb5bd;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n flex: 1 1 auto;\n}\n.btn-group > .btn-check:checked + .btn,\n.btn-group > .btn-check:focus + .btn,\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn-check:checked + .btn,\n.btn-group-vertical > .btn-check:focus + .btn,\n.btn-group-vertical > .btn:hover,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 1;\n}\n\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group {\n border-radius: var(--bs-border-radius);\n}\n.btn-group > :not(.btn-check:first-child) + .btn,\n.btn-group > .btn-group:not(:first-child) {\n margin-left: calc(var(--bs-border-width) * -1);\n}\n.btn-group > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group > .btn.dropdown-toggle-split:first-child,\n.btn-group > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:nth-child(n+3),\n.btn-group > :not(.btn-check) + .btn,\n.btn-group > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after {\n margin-left: 0;\n}\n.dropstart .dropdown-toggle-split::before {\n margin-right: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group {\n width: 100%;\n}\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) {\n margin-top: calc(var(--bs-border-width) * -1);\n}\n.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group-vertical > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn ~ .btn,\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav {\n --bs-nav-link-padding-x: 1rem;\n --bs-nav-link-padding-y: 0.5rem;\n --bs-nav-link-font-weight: ;\n --bs-nav-link-color: var(--bs-link-color);\n --bs-nav-link-hover-color: var(--bs-link-hover-color);\n --bs-nav-link-disabled-color: var(--bs-secondary-color);\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);\n font-size: var(--bs-nav-link-font-size);\n font-weight: var(--bs-nav-link-font-weight);\n color: var(--bs-nav-link-color);\n text-decoration: none;\n background: none;\n border: 0;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .nav-link {\n transition: none;\n }\n}\n.nav-link:hover, .nav-link:focus {\n color: var(--bs-nav-link-hover-color);\n}\n.nav-link:focus-visible {\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.nav-link.disabled, .nav-link:disabled {\n color: var(--bs-nav-link-disabled-color);\n pointer-events: none;\n cursor: default;\n}\n\n.nav-tabs {\n --bs-nav-tabs-border-width: var(--bs-border-width);\n --bs-nav-tabs-border-color: var(--bs-border-color);\n --bs-nav-tabs-border-radius: var(--bs-border-radius);\n --bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);\n --bs-nav-tabs-link-active-color: var(--bs-emphasis-color);\n --bs-nav-tabs-link-active-bg: var(--bs-body-bg);\n --bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);\n border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color);\n}\n.nav-tabs .nav-link {\n margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width));\n border: var(--bs-nav-tabs-border-width) solid transparent;\n border-top-left-radius: var(--bs-nav-tabs-border-radius);\n border-top-right-radius: var(--bs-nav-tabs-border-radius);\n}\n.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {\n isolation: isolate;\n border-color: var(--bs-nav-tabs-link-hover-border-color);\n}\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: var(--bs-nav-tabs-link-active-color);\n background-color: var(--bs-nav-tabs-link-active-bg);\n border-color: var(--bs-nav-tabs-link-active-border-color);\n}\n.nav-tabs .dropdown-menu {\n margin-top: calc(-1 * var(--bs-nav-tabs-border-width));\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills {\n --bs-nav-pills-border-radius: var(--bs-border-radius);\n --bs-nav-pills-link-active-color: #fff;\n --bs-nav-pills-link-active-bg: #0d6efd;\n}\n.nav-pills .nav-link {\n border-radius: var(--bs-nav-pills-border-radius);\n}\n.nav-pills .nav-link.active,\n.nav-pills .show > .nav-link {\n color: var(--bs-nav-pills-link-active-color);\n background-color: var(--bs-nav-pills-link-active-bg);\n}\n\n.nav-underline {\n --bs-nav-underline-gap: 1rem;\n --bs-nav-underline-border-width: 0.125rem;\n --bs-nav-underline-link-active-color: var(--bs-emphasis-color);\n gap: var(--bs-nav-underline-gap);\n}\n.nav-underline .nav-link {\n padding-right: 0;\n padding-left: 0;\n border-bottom: var(--bs-nav-underline-border-width) solid transparent;\n}\n.nav-underline .nav-link:hover, .nav-underline .nav-link:focus {\n border-bottom-color: currentcolor;\n}\n.nav-underline .nav-link.active,\n.nav-underline .show > .nav-link {\n font-weight: 700;\n color: var(--bs-nav-underline-link-active-color);\n border-bottom-color: currentcolor;\n}\n\n.nav-fill > .nav-link,\n.nav-fill .nav-item {\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified > .nav-link,\n.nav-justified .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n}\n\n.nav-fill .nav-item .nav-link,\n.nav-justified .nav-item .nav-link {\n width: 100%;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n --bs-navbar-padding-x: 0;\n --bs-navbar-padding-y: 0.5rem;\n --bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65);\n --bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8);\n --bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3);\n --bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);\n --bs-navbar-brand-padding-y: 0.3125rem;\n --bs-navbar-brand-margin-end: 1rem;\n --bs-navbar-brand-font-size: 1.25rem;\n --bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);\n --bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);\n --bs-navbar-nav-link-padding-x: 0.5rem;\n --bs-navbar-toggler-padding-y: 0.25rem;\n --bs-navbar-toggler-padding-x: 0.75rem;\n --bs-navbar-toggler-font-size: 1.25rem;\n --bs-navbar-toggler-icon-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n --bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15);\n --bs-navbar-toggler-border-radius: var(--bs-border-radius);\n --bs-navbar-toggler-focus-width: 0.25rem;\n --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x);\n}\n.navbar > .container,\n.navbar > .container-fluid,\n.navbar > .container-sm,\n.navbar > .container-md,\n.navbar > .container-lg,\n.navbar > .container-xl,\n.navbar > .container-xxl {\n display: flex;\n flex-wrap: inherit;\n align-items: center;\n justify-content: space-between;\n}\n.navbar-brand {\n padding-top: var(--bs-navbar-brand-padding-y);\n padding-bottom: var(--bs-navbar-brand-padding-y);\n margin-right: var(--bs-navbar-brand-margin-end);\n font-size: var(--bs-navbar-brand-font-size);\n color: var(--bs-navbar-brand-color);\n text-decoration: none;\n white-space: nowrap;\n}\n.navbar-brand:hover, .navbar-brand:focus {\n color: var(--bs-navbar-brand-hover-color);\n}\n\n.navbar-nav {\n --bs-nav-link-padding-x: 0;\n --bs-nav-link-padding-y: 0.5rem;\n --bs-nav-link-font-weight: ;\n --bs-nav-link-color: var(--bs-navbar-color);\n --bs-nav-link-hover-color: var(--bs-navbar-hover-color);\n --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.navbar-nav .nav-link.active, .navbar-nav .nav-link.show {\n color: var(--bs-navbar-active-color);\n}\n.navbar-nav .dropdown-menu {\n position: static;\n}\n\n.navbar-text {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n color: var(--bs-navbar-color);\n}\n.navbar-text a,\n.navbar-text a:hover,\n.navbar-text a:focus {\n color: var(--bs-navbar-active-color);\n}\n\n.navbar-collapse {\n flex-basis: 100%;\n flex-grow: 1;\n align-items: center;\n}\n\n.navbar-toggler {\n padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);\n font-size: var(--bs-navbar-toggler-font-size);\n line-height: 1;\n color: var(--bs-navbar-color);\n background-color: transparent;\n border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);\n border-radius: var(--bs-navbar-toggler-border-radius);\n transition: var(--bs-navbar-toggler-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .navbar-toggler {\n transition: none;\n }\n}\n.navbar-toggler:hover {\n text-decoration: none;\n}\n.navbar-toggler:focus {\n text-decoration: none;\n outline: 0;\n box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width);\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n background-image: var(--bs-navbar-toggler-icon-bg);\n background-repeat: no-repeat;\n background-position: center;\n background-size: 100%;\n}\n\n.navbar-nav-scroll {\n max-height: var(--bs-scroll-height, 75vh);\n overflow-y: auto;\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-sm .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-sm .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n .navbar-expand-sm .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-sm .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-sm .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 768px) {\n .navbar-expand-md {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-md .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-md .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n .navbar-expand-md .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-md .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-md .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 992px) {\n .navbar-expand-lg {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-lg .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-lg .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n .navbar-expand-lg .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-lg .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-lg .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-xl .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-xl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n .navbar-expand-xl .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-xl .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-xl .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 1400px) {\n .navbar-expand-xxl {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xxl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xxl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xxl .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-xxl .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-xxl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xxl .navbar-toggler {\n display: none;\n }\n .navbar-expand-xxl .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-xxl .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-xxl .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n.navbar-expand {\n flex-wrap: nowrap;\n justify-content: flex-start;\n}\n.navbar-expand .navbar-nav {\n flex-direction: row;\n}\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n.navbar-expand .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n}\n.navbar-expand .navbar-nav-scroll {\n overflow: visible;\n}\n.navbar-expand .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n}\n.navbar-expand .navbar-toggler {\n display: none;\n}\n.navbar-expand .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n}\n.navbar-expand .offcanvas .offcanvas-header {\n display: none;\n}\n.navbar-expand .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n}\n\n.navbar-dark,\n.navbar[data-bs-theme=dark] {\n --bs-navbar-color: rgba(255, 255, 255, 0.55);\n --bs-navbar-hover-color: rgba(255, 255, 255, 0.75);\n --bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);\n --bs-navbar-active-color: #fff;\n --bs-navbar-brand-color: #fff;\n --bs-navbar-brand-hover-color: #fff;\n --bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1);\n --bs-navbar-toggler-icon-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n[data-bs-theme=dark] .navbar-toggler-icon {\n --bs-navbar-toggler-icon-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.card {\n --bs-card-spacer-y: 1rem;\n --bs-card-spacer-x: 1rem;\n --bs-card-title-spacer-y: 0.5rem;\n --bs-card-title-color: ;\n --bs-card-subtitle-color: ;\n --bs-card-border-width: var(--bs-border-width);\n --bs-card-border-color: var(--bs-border-color-translucent);\n --bs-card-border-radius: var(--bs-border-radius);\n --bs-card-box-shadow: ;\n --bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));\n --bs-card-cap-padding-y: 0.5rem;\n --bs-card-cap-padding-x: 1rem;\n --bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03);\n --bs-card-cap-color: ;\n --bs-card-height: ;\n --bs-card-color: ;\n --bs-card-bg: var(--bs-body-bg);\n --bs-card-img-overlay-padding: 1rem;\n --bs-card-group-margin: 0.75rem;\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0;\n height: var(--bs-card-height);\n color: var(--bs-body-color);\n word-wrap: break-word;\n background-color: var(--bs-card-bg);\n background-clip: border-box;\n border: var(--bs-card-border-width) solid var(--bs-card-border-color);\n border-radius: var(--bs-card-border-radius);\n}\n.card > hr {\n margin-right: 0;\n margin-left: 0;\n}\n.card > .list-group {\n border-top: inherit;\n border-bottom: inherit;\n}\n.card > .list-group:first-child {\n border-top-width: 0;\n border-top-left-radius: var(--bs-card-inner-border-radius);\n border-top-right-radius: var(--bs-card-inner-border-radius);\n}\n.card > .list-group:last-child {\n border-bottom-width: 0;\n border-bottom-right-radius: var(--bs-card-inner-border-radius);\n border-bottom-left-radius: var(--bs-card-inner-border-radius);\n}\n.card > .card-header + .list-group,\n.card > .list-group + .card-footer {\n border-top: 0;\n}\n\n.card-body {\n flex: 1 1 auto;\n padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x);\n color: var(--bs-card-color);\n}\n\n.card-title {\n margin-bottom: var(--bs-card-title-spacer-y);\n color: var(--bs-card-title-color);\n}\n\n.card-subtitle {\n margin-top: calc(-0.5 * var(--bs-card-title-spacer-y));\n margin-bottom: 0;\n color: var(--bs-card-subtitle-color);\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link + .card-link {\n margin-left: var(--bs-card-spacer-x);\n}\n\n.card-header {\n padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);\n margin-bottom: 0;\n color: var(--bs-card-cap-color);\n background-color: var(--bs-card-cap-bg);\n border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color);\n}\n.card-header:first-child {\n border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0;\n}\n\n.card-footer {\n padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);\n color: var(--bs-card-cap-color);\n background-color: var(--bs-card-cap-bg);\n border-top: var(--bs-card-border-width) solid var(--bs-card-border-color);\n}\n.card-footer:last-child {\n border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius);\n}\n\n.card-header-tabs {\n margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));\n margin-bottom: calc(-1 * var(--bs-card-cap-padding-y));\n margin-left: calc(-0.5 * var(--bs-card-cap-padding-x));\n border-bottom: 0;\n}\n.card-header-tabs .nav-link.active {\n background-color: var(--bs-card-bg);\n border-bottom-color: var(--bs-card-bg);\n}\n\n.card-header-pills {\n margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));\n margin-left: calc(-0.5 * var(--bs-card-cap-padding-x));\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: var(--bs-card-img-overlay-padding);\n border-radius: var(--bs-card-inner-border-radius);\n}\n\n.card-img,\n.card-img-top,\n.card-img-bottom {\n width: 100%;\n}\n\n.card-img,\n.card-img-top {\n border-top-left-radius: var(--bs-card-inner-border-radius);\n border-top-right-radius: var(--bs-card-inner-border-radius);\n}\n\n.card-img,\n.card-img-bottom {\n border-bottom-right-radius: var(--bs-card-inner-border-radius);\n border-bottom-left-radius: var(--bs-card-inner-border-radius);\n}\n\n.card-group > .card {\n margin-bottom: var(--bs-card-group-margin);\n}\n@media (min-width: 576px) {\n .card-group {\n display: flex;\n flex-flow: row wrap;\n }\n .card-group > .card {\n flex: 1 0 0%;\n margin-bottom: 0;\n }\n .card-group > .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group > .card:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-top,\n .card-group > .card:not(:last-child) .card-header {\n border-top-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-bottom,\n .card-group > .card:not(:last-child) .card-footer {\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-top,\n .card-group > .card:not(:first-child) .card-header {\n border-top-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-bottom,\n .card-group > .card:not(:first-child) .card-footer {\n border-bottom-left-radius: 0;\n }\n}\n\n.accordion {\n --bs-accordion-color: var(--bs-body-color);\n --bs-accordion-bg: var(--bs-body-bg);\n --bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;\n --bs-accordion-border-color: var(--bs-border-color);\n --bs-accordion-border-width: var(--bs-border-width);\n --bs-accordion-border-radius: var(--bs-border-radius);\n --bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));\n --bs-accordion-btn-padding-x: 1.25rem;\n --bs-accordion-btn-padding-y: 1rem;\n --bs-accordion-btn-color: var(--bs-body-color);\n --bs-accordion-btn-bg: var(--bs-accordion-bg);\n --bs-accordion-btn-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e\");\n --bs-accordion-btn-icon-width: 1.25rem;\n --bs-accordion-btn-icon-transform: rotate(-180deg);\n --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;\n --bs-accordion-btn-active-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e\");\n --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n --bs-accordion-body-padding-x: 1.25rem;\n --bs-accordion-body-padding-y: 1rem;\n --bs-accordion-active-color: var(--bs-primary-text-emphasis);\n --bs-accordion-active-bg: var(--bs-primary-bg-subtle);\n}\n\n.accordion-button {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);\n font-size: 1rem;\n color: var(--bs-accordion-btn-color);\n text-align: left;\n background-color: var(--bs-accordion-btn-bg);\n border: 0;\n border-radius: 0;\n overflow-anchor: none;\n transition: var(--bs-accordion-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .accordion-button {\n transition: none;\n }\n}\n.accordion-button:not(.collapsed) {\n color: var(--bs-accordion-active-color);\n background-color: var(--bs-accordion-active-bg);\n box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color);\n}\n.accordion-button:not(.collapsed)::after {\n background-image: var(--bs-accordion-btn-active-icon);\n transform: var(--bs-accordion-btn-icon-transform);\n}\n.accordion-button::after {\n flex-shrink: 0;\n width: var(--bs-accordion-btn-icon-width);\n height: var(--bs-accordion-btn-icon-width);\n margin-left: auto;\n content: \"\";\n background-image: var(--bs-accordion-btn-icon);\n background-repeat: no-repeat;\n background-size: var(--bs-accordion-btn-icon-width);\n transition: var(--bs-accordion-btn-icon-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .accordion-button::after {\n transition: none;\n }\n}\n.accordion-button:hover {\n z-index: 2;\n}\n.accordion-button:focus {\n z-index: 3;\n outline: 0;\n box-shadow: var(--bs-accordion-btn-focus-box-shadow);\n}\n\n.accordion-header {\n margin-bottom: 0;\n}\n\n.accordion-item {\n color: var(--bs-accordion-color);\n background-color: var(--bs-accordion-bg);\n border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color);\n}\n.accordion-item:first-of-type {\n border-top-left-radius: var(--bs-accordion-border-radius);\n border-top-right-radius: var(--bs-accordion-border-radius);\n}\n.accordion-item:first-of-type > .accordion-header .accordion-button {\n border-top-left-radius: var(--bs-accordion-inner-border-radius);\n border-top-right-radius: var(--bs-accordion-inner-border-radius);\n}\n.accordion-item:not(:first-of-type) {\n border-top: 0;\n}\n.accordion-item:last-of-type {\n border-bottom-right-radius: var(--bs-accordion-border-radius);\n border-bottom-left-radius: var(--bs-accordion-border-radius);\n}\n.accordion-item:last-of-type > .accordion-header .accordion-button.collapsed {\n border-bottom-right-radius: var(--bs-accordion-inner-border-radius);\n border-bottom-left-radius: var(--bs-accordion-inner-border-radius);\n}\n.accordion-item:last-of-type > .accordion-collapse {\n border-bottom-right-radius: var(--bs-accordion-border-radius);\n border-bottom-left-radius: var(--bs-accordion-border-radius);\n}\n\n.accordion-body {\n padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x);\n}\n\n.accordion-flush > .accordion-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n.accordion-flush > .accordion-item:first-child {\n border-top: 0;\n}\n.accordion-flush > .accordion-item:last-child {\n border-bottom: 0;\n}\n.accordion-flush > .accordion-item > .accordion-header .accordion-button, .accordion-flush > .accordion-item > .accordion-header .accordion-button.collapsed {\n border-radius: 0;\n}\n.accordion-flush > .accordion-item > .accordion-collapse {\n border-radius: 0;\n}\n\n[data-bs-theme=dark] .accordion-button::after {\n --bs-accordion-btn-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n --bs-accordion-btn-active-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n}\n\n.breadcrumb {\n --bs-breadcrumb-padding-x: 0;\n --bs-breadcrumb-padding-y: 0;\n --bs-breadcrumb-margin-bottom: 1rem;\n --bs-breadcrumb-bg: ;\n --bs-breadcrumb-border-radius: ;\n --bs-breadcrumb-divider-color: var(--bs-secondary-color);\n --bs-breadcrumb-item-padding-x: 0.5rem;\n --bs-breadcrumb-item-active-color: var(--bs-secondary-color);\n display: flex;\n flex-wrap: wrap;\n padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);\n margin-bottom: var(--bs-breadcrumb-margin-bottom);\n font-size: var(--bs-breadcrumb-font-size);\n list-style: none;\n background-color: var(--bs-breadcrumb-bg);\n border-radius: var(--bs-breadcrumb-border-radius);\n}\n\n.breadcrumb-item + .breadcrumb-item {\n padding-left: var(--bs-breadcrumb-item-padding-x);\n}\n.breadcrumb-item + .breadcrumb-item::before {\n float: left;\n padding-right: var(--bs-breadcrumb-item-padding-x);\n color: var(--bs-breadcrumb-divider-color);\n content: var(--bs-breadcrumb-divider, \"/\") /* rtl: var(--bs-breadcrumb-divider, \"/\") */;\n}\n.breadcrumb-item.active {\n color: var(--bs-breadcrumb-item-active-color);\n}\n\n.pagination {\n --bs-pagination-padding-x: 0.75rem;\n --bs-pagination-padding-y: 0.375rem;\n --bs-pagination-font-size: 1rem;\n --bs-pagination-color: var(--bs-link-color);\n --bs-pagination-bg: var(--bs-body-bg);\n --bs-pagination-border-width: var(--bs-border-width);\n --bs-pagination-border-color: var(--bs-border-color);\n --bs-pagination-border-radius: var(--bs-border-radius);\n --bs-pagination-hover-color: var(--bs-link-hover-color);\n --bs-pagination-hover-bg: var(--bs-tertiary-bg);\n --bs-pagination-hover-border-color: var(--bs-border-color);\n --bs-pagination-focus-color: var(--bs-link-hover-color);\n --bs-pagination-focus-bg: var(--bs-secondary-bg);\n --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n --bs-pagination-active-color: #fff;\n --bs-pagination-active-bg: #0d6efd;\n --bs-pagination-active-border-color: #0d6efd;\n --bs-pagination-disabled-color: var(--bs-secondary-color);\n --bs-pagination-disabled-bg: var(--bs-secondary-bg);\n --bs-pagination-disabled-border-color: var(--bs-border-color);\n display: flex;\n padding-left: 0;\n list-style: none;\n}\n\n.page-link {\n position: relative;\n display: block;\n padding: var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);\n font-size: var(--bs-pagination-font-size);\n color: var(--bs-pagination-color);\n text-decoration: none;\n background-color: var(--bs-pagination-bg);\n border: var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .page-link {\n transition: none;\n }\n}\n.page-link:hover {\n z-index: 2;\n color: var(--bs-pagination-hover-color);\n background-color: var(--bs-pagination-hover-bg);\n border-color: var(--bs-pagination-hover-border-color);\n}\n.page-link:focus {\n z-index: 3;\n color: var(--bs-pagination-focus-color);\n background-color: var(--bs-pagination-focus-bg);\n outline: 0;\n box-shadow: var(--bs-pagination-focus-box-shadow);\n}\n.page-link.active, .active > .page-link {\n z-index: 3;\n color: var(--bs-pagination-active-color);\n background-color: var(--bs-pagination-active-bg);\n border-color: var(--bs-pagination-active-border-color);\n}\n.page-link.disabled, .disabled > .page-link {\n color: var(--bs-pagination-disabled-color);\n pointer-events: none;\n background-color: var(--bs-pagination-disabled-bg);\n border-color: var(--bs-pagination-disabled-border-color);\n}\n\n.page-item:not(:first-child) .page-link {\n margin-left: calc(var(--bs-border-width) * -1);\n}\n.page-item:first-child .page-link {\n border-top-left-radius: var(--bs-pagination-border-radius);\n border-bottom-left-radius: var(--bs-pagination-border-radius);\n}\n.page-item:last-child .page-link {\n border-top-right-radius: var(--bs-pagination-border-radius);\n border-bottom-right-radius: var(--bs-pagination-border-radius);\n}\n\n.pagination-lg {\n --bs-pagination-padding-x: 1.5rem;\n --bs-pagination-padding-y: 0.75rem;\n --bs-pagination-font-size: 1.25rem;\n --bs-pagination-border-radius: var(--bs-border-radius-lg);\n}\n\n.pagination-sm {\n --bs-pagination-padding-x: 0.5rem;\n --bs-pagination-padding-y: 0.25rem;\n --bs-pagination-font-size: 0.875rem;\n --bs-pagination-border-radius: var(--bs-border-radius-sm);\n}\n\n.badge {\n --bs-badge-padding-x: 0.65em;\n --bs-badge-padding-y: 0.35em;\n --bs-badge-font-size: 0.75em;\n --bs-badge-font-weight: 700;\n --bs-badge-color: #fff;\n --bs-badge-border-radius: var(--bs-border-radius);\n display: inline-block;\n padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x);\n font-size: var(--bs-badge-font-size);\n font-weight: var(--bs-badge-font-weight);\n line-height: 1;\n color: var(--bs-badge-color);\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: var(--bs-badge-border-radius);\n}\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.alert {\n --bs-alert-bg: transparent;\n --bs-alert-padding-x: 1rem;\n --bs-alert-padding-y: 1rem;\n --bs-alert-margin-bottom: 1rem;\n --bs-alert-color: inherit;\n --bs-alert-border-color: transparent;\n --bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);\n --bs-alert-border-radius: var(--bs-border-radius);\n --bs-alert-link-color: inherit;\n position: relative;\n padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x);\n margin-bottom: var(--bs-alert-margin-bottom);\n color: var(--bs-alert-color);\n background-color: var(--bs-alert-bg);\n border: var(--bs-alert-border);\n border-radius: var(--bs-alert-border-radius);\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: 700;\n color: var(--bs-alert-link-color);\n}\n\n.alert-dismissible {\n padding-right: 3rem;\n}\n.alert-dismissible .btn-close {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n padding: 1.25rem 1rem;\n}\n\n.alert-primary {\n --bs-alert-color: var(--bs-primary-text-emphasis);\n --bs-alert-bg: var(--bs-primary-bg-subtle);\n --bs-alert-border-color: var(--bs-primary-border-subtle);\n --bs-alert-link-color: var(--bs-primary-text-emphasis);\n}\n\n.alert-secondary {\n --bs-alert-color: var(--bs-secondary-text-emphasis);\n --bs-alert-bg: var(--bs-secondary-bg-subtle);\n --bs-alert-border-color: var(--bs-secondary-border-subtle);\n --bs-alert-link-color: var(--bs-secondary-text-emphasis);\n}\n\n.alert-success {\n --bs-alert-color: var(--bs-success-text-emphasis);\n --bs-alert-bg: var(--bs-success-bg-subtle);\n --bs-alert-border-color: var(--bs-success-border-subtle);\n --bs-alert-link-color: var(--bs-success-text-emphasis);\n}\n\n.alert-info {\n --bs-alert-color: var(--bs-info-text-emphasis);\n --bs-alert-bg: var(--bs-info-bg-subtle);\n --bs-alert-border-color: var(--bs-info-border-subtle);\n --bs-alert-link-color: var(--bs-info-text-emphasis);\n}\n\n.alert-warning {\n --bs-alert-color: var(--bs-warning-text-emphasis);\n --bs-alert-bg: var(--bs-warning-bg-subtle);\n --bs-alert-border-color: var(--bs-warning-border-subtle);\n --bs-alert-link-color: var(--bs-warning-text-emphasis);\n}\n\n.alert-danger {\n --bs-alert-color: var(--bs-danger-text-emphasis);\n --bs-alert-bg: var(--bs-danger-bg-subtle);\n --bs-alert-border-color: var(--bs-danger-border-subtle);\n --bs-alert-link-color: var(--bs-danger-text-emphasis);\n}\n\n.alert-light {\n --bs-alert-color: var(--bs-light-text-emphasis);\n --bs-alert-bg: var(--bs-light-bg-subtle);\n --bs-alert-border-color: var(--bs-light-border-subtle);\n --bs-alert-link-color: var(--bs-light-text-emphasis);\n}\n\n.alert-dark {\n --bs-alert-color: var(--bs-dark-text-emphasis);\n --bs-alert-bg: var(--bs-dark-bg-subtle);\n --bs-alert-border-color: var(--bs-dark-border-subtle);\n --bs-alert-link-color: var(--bs-dark-text-emphasis);\n}\n\n@keyframes progress-bar-stripes {\n 0% {\n background-position-x: 1rem;\n }\n}\n.progress,\n.progress-stacked {\n --bs-progress-height: 1rem;\n --bs-progress-font-size: 0.75rem;\n --bs-progress-bg: var(--bs-secondary-bg);\n --bs-progress-border-radius: var(--bs-border-radius);\n --bs-progress-box-shadow: var(--bs-box-shadow-inset);\n --bs-progress-bar-color: #fff;\n --bs-progress-bar-bg: #0d6efd;\n --bs-progress-bar-transition: width 0.6s ease;\n display: flex;\n height: var(--bs-progress-height);\n overflow: hidden;\n font-size: var(--bs-progress-font-size);\n background-color: var(--bs-progress-bg);\n border-radius: var(--bs-progress-border-radius);\n}\n\n.progress-bar {\n display: flex;\n flex-direction: column;\n justify-content: center;\n overflow: hidden;\n color: var(--bs-progress-bar-color);\n text-align: center;\n white-space: nowrap;\n background-color: var(--bs-progress-bar-bg);\n transition: var(--bs-progress-bar-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: var(--bs-progress-height) var(--bs-progress-height);\n}\n\n.progress-stacked > .progress {\n overflow: visible;\n}\n\n.progress-stacked > .progress > .progress-bar {\n width: 100%;\n}\n\n.progress-bar-animated {\n animation: 1s linear infinite progress-bar-stripes;\n}\n@media (prefers-reduced-motion: reduce) {\n .progress-bar-animated {\n animation: none;\n }\n}\n\n.list-group {\n --bs-list-group-color: var(--bs-body-color);\n --bs-list-group-bg: var(--bs-body-bg);\n --bs-list-group-border-color: var(--bs-border-color);\n --bs-list-group-border-width: var(--bs-border-width);\n --bs-list-group-border-radius: var(--bs-border-radius);\n --bs-list-group-item-padding-x: 1rem;\n --bs-list-group-item-padding-y: 0.5rem;\n --bs-list-group-action-color: var(--bs-secondary-color);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);\n --bs-list-group-action-active-color: var(--bs-body-color);\n --bs-list-group-action-active-bg: var(--bs-secondary-bg);\n --bs-list-group-disabled-color: var(--bs-secondary-color);\n --bs-list-group-disabled-bg: var(--bs-body-bg);\n --bs-list-group-active-color: #fff;\n --bs-list-group-active-bg: #0d6efd;\n --bs-list-group-active-border-color: #0d6efd;\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n border-radius: var(--bs-list-group-border-radius);\n}\n\n.list-group-numbered {\n list-style-type: none;\n counter-reset: section;\n}\n.list-group-numbered > .list-group-item::before {\n content: counters(section, \".\") \". \";\n counter-increment: section;\n}\n\n.list-group-item-action {\n width: 100%;\n color: var(--bs-list-group-action-color);\n text-align: inherit;\n}\n.list-group-item-action:hover, .list-group-item-action:focus {\n z-index: 1;\n color: var(--bs-list-group-action-hover-color);\n text-decoration: none;\n background-color: var(--bs-list-group-action-hover-bg);\n}\n.list-group-item-action:active {\n color: var(--bs-list-group-action-active-color);\n background-color: var(--bs-list-group-action-active-bg);\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);\n color: var(--bs-list-group-color);\n text-decoration: none;\n background-color: var(--bs-list-group-bg);\n border: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color);\n}\n.list-group-item:first-child {\n border-top-left-radius: inherit;\n border-top-right-radius: inherit;\n}\n.list-group-item:last-child {\n border-bottom-right-radius: inherit;\n border-bottom-left-radius: inherit;\n}\n.list-group-item.disabled, .list-group-item:disabled {\n color: var(--bs-list-group-disabled-color);\n pointer-events: none;\n background-color: var(--bs-list-group-disabled-bg);\n}\n.list-group-item.active {\n z-index: 2;\n color: var(--bs-list-group-active-color);\n background-color: var(--bs-list-group-active-bg);\n border-color: var(--bs-list-group-active-border-color);\n}\n.list-group-item + .list-group-item {\n border-top-width: 0;\n}\n.list-group-item + .list-group-item.active {\n margin-top: calc(-1 * var(--bs-list-group-border-width));\n border-top-width: var(--bs-list-group-border-width);\n}\n\n.list-group-horizontal {\n flex-direction: row;\n}\n.list-group-horizontal > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n}\n.list-group-horizontal > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n}\n.list-group-horizontal > .list-group-item.active {\n margin-top: 0;\n}\n.list-group-horizontal > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n}\n.list-group-horizontal > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n}\n\n@media (min-width: 576px) {\n .list-group-horizontal-sm {\n flex-direction: row;\n }\n .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-sm > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-sm > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-sm > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 768px) {\n .list-group-horizontal-md {\n flex-direction: row;\n }\n .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-md > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-md > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-md > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 992px) {\n .list-group-horizontal-lg {\n flex-direction: row;\n }\n .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-lg > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-lg > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-lg > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 1200px) {\n .list-group-horizontal-xl {\n flex-direction: row;\n }\n .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-xl > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-xl > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-xl > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 1400px) {\n .list-group-horizontal-xxl {\n flex-direction: row;\n }\n .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-xxl > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-xxl > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-xxl > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n.list-group-flush {\n border-radius: 0;\n}\n.list-group-flush > .list-group-item {\n border-width: 0 0 var(--bs-list-group-border-width);\n}\n.list-group-flush > .list-group-item:last-child {\n border-bottom-width: 0;\n}\n\n.list-group-item-primary {\n --bs-list-group-color: var(--bs-primary-text-emphasis);\n --bs-list-group-bg: var(--bs-primary-bg-subtle);\n --bs-list-group-border-color: var(--bs-primary-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-primary-border-subtle);\n --bs-list-group-active-color: var(--bs-primary-bg-subtle);\n --bs-list-group-active-bg: var(--bs-primary-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-primary-text-emphasis);\n}\n\n.list-group-item-secondary {\n --bs-list-group-color: var(--bs-secondary-text-emphasis);\n --bs-list-group-bg: var(--bs-secondary-bg-subtle);\n --bs-list-group-border-color: var(--bs-secondary-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);\n --bs-list-group-active-color: var(--bs-secondary-bg-subtle);\n --bs-list-group-active-bg: var(--bs-secondary-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-secondary-text-emphasis);\n}\n\n.list-group-item-success {\n --bs-list-group-color: var(--bs-success-text-emphasis);\n --bs-list-group-bg: var(--bs-success-bg-subtle);\n --bs-list-group-border-color: var(--bs-success-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-success-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-success-border-subtle);\n --bs-list-group-active-color: var(--bs-success-bg-subtle);\n --bs-list-group-active-bg: var(--bs-success-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-success-text-emphasis);\n}\n\n.list-group-item-info {\n --bs-list-group-color: var(--bs-info-text-emphasis);\n --bs-list-group-bg: var(--bs-info-bg-subtle);\n --bs-list-group-border-color: var(--bs-info-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-info-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-info-border-subtle);\n --bs-list-group-active-color: var(--bs-info-bg-subtle);\n --bs-list-group-active-bg: var(--bs-info-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-info-text-emphasis);\n}\n\n.list-group-item-warning {\n --bs-list-group-color: var(--bs-warning-text-emphasis);\n --bs-list-group-bg: var(--bs-warning-bg-subtle);\n --bs-list-group-border-color: var(--bs-warning-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-warning-border-subtle);\n --bs-list-group-active-color: var(--bs-warning-bg-subtle);\n --bs-list-group-active-bg: var(--bs-warning-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-warning-text-emphasis);\n}\n\n.list-group-item-danger {\n --bs-list-group-color: var(--bs-danger-text-emphasis);\n --bs-list-group-bg: var(--bs-danger-bg-subtle);\n --bs-list-group-border-color: var(--bs-danger-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-danger-border-subtle);\n --bs-list-group-active-color: var(--bs-danger-bg-subtle);\n --bs-list-group-active-bg: var(--bs-danger-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-danger-text-emphasis);\n}\n\n.list-group-item-light {\n --bs-list-group-color: var(--bs-light-text-emphasis);\n --bs-list-group-bg: var(--bs-light-bg-subtle);\n --bs-list-group-border-color: var(--bs-light-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-light-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-light-border-subtle);\n --bs-list-group-active-color: var(--bs-light-bg-subtle);\n --bs-list-group-active-bg: var(--bs-light-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-light-text-emphasis);\n}\n\n.list-group-item-dark {\n --bs-list-group-color: var(--bs-dark-text-emphasis);\n --bs-list-group-bg: var(--bs-dark-bg-subtle);\n --bs-list-group-border-color: var(--bs-dark-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-dark-border-subtle);\n --bs-list-group-active-color: var(--bs-dark-bg-subtle);\n --bs-list-group-active-bg: var(--bs-dark-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-dark-text-emphasis);\n}\n\n.btn-close {\n --bs-btn-close-color: #000;\n --bs-btn-close-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e\");\n --bs-btn-close-opacity: 0.5;\n --bs-btn-close-hover-opacity: 0.75;\n --bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n --bs-btn-close-focus-opacity: 1;\n --bs-btn-close-disabled-opacity: 0.25;\n --bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);\n box-sizing: content-box;\n width: 1em;\n height: 1em;\n padding: 0.25em 0.25em;\n color: var(--bs-btn-close-color);\n background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat;\n border: 0;\n border-radius: 0.375rem;\n opacity: var(--bs-btn-close-opacity);\n}\n.btn-close:hover {\n color: var(--bs-btn-close-color);\n text-decoration: none;\n opacity: var(--bs-btn-close-hover-opacity);\n}\n.btn-close:focus {\n outline: 0;\n box-shadow: var(--bs-btn-close-focus-shadow);\n opacity: var(--bs-btn-close-focus-opacity);\n}\n.btn-close:disabled, .btn-close.disabled {\n pointer-events: none;\n user-select: none;\n opacity: var(--bs-btn-close-disabled-opacity);\n}\n\n.btn-close-white {\n filter: var(--bs-btn-close-white-filter);\n}\n\n[data-bs-theme=dark] .btn-close {\n filter: var(--bs-btn-close-white-filter);\n}\n\n.toast {\n --bs-toast-zindex: 1090;\n --bs-toast-padding-x: 0.75rem;\n --bs-toast-padding-y: 0.5rem;\n --bs-toast-spacing: 1.5rem;\n --bs-toast-max-width: 350px;\n --bs-toast-font-size: 0.875rem;\n --bs-toast-color: ;\n --bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);\n --bs-toast-border-width: var(--bs-border-width);\n --bs-toast-border-color: var(--bs-border-color-translucent);\n --bs-toast-border-radius: var(--bs-border-radius);\n --bs-toast-box-shadow: var(--bs-box-shadow);\n --bs-toast-header-color: var(--bs-secondary-color);\n --bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);\n --bs-toast-header-border-color: var(--bs-border-color-translucent);\n width: var(--bs-toast-max-width);\n max-width: 100%;\n font-size: var(--bs-toast-font-size);\n color: var(--bs-toast-color);\n pointer-events: auto;\n background-color: var(--bs-toast-bg);\n background-clip: padding-box;\n border: var(--bs-toast-border-width) solid var(--bs-toast-border-color);\n box-shadow: var(--bs-toast-box-shadow);\n border-radius: var(--bs-toast-border-radius);\n}\n.toast.showing {\n opacity: 0;\n}\n.toast:not(.show) {\n display: none;\n}\n\n.toast-container {\n --bs-toast-zindex: 1090;\n position: absolute;\n z-index: var(--bs-toast-zindex);\n width: max-content;\n max-width: 100%;\n pointer-events: none;\n}\n.toast-container > :not(:last-child) {\n margin-bottom: var(--bs-toast-spacing);\n}\n\n.toast-header {\n display: flex;\n align-items: center;\n padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x);\n color: var(--bs-toast-header-color);\n background-color: var(--bs-toast-header-bg);\n background-clip: padding-box;\n border-bottom: var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);\n border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));\n border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));\n}\n.toast-header .btn-close {\n margin-right: calc(-0.5 * var(--bs-toast-padding-x));\n margin-left: var(--bs-toast-padding-x);\n}\n\n.toast-body {\n padding: var(--bs-toast-padding-x);\n word-wrap: break-word;\n}\n\n.modal {\n --bs-modal-zindex: 1055;\n --bs-modal-width: 500px;\n --bs-modal-padding: 1rem;\n --bs-modal-margin: 0.5rem;\n --bs-modal-color: ;\n --bs-modal-bg: var(--bs-body-bg);\n --bs-modal-border-color: var(--bs-border-color-translucent);\n --bs-modal-border-width: var(--bs-border-width);\n --bs-modal-border-radius: var(--bs-border-radius-lg);\n --bs-modal-box-shadow: var(--bs-box-shadow-sm);\n --bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));\n --bs-modal-header-padding-x: 1rem;\n --bs-modal-header-padding-y: 1rem;\n --bs-modal-header-padding: 1rem 1rem;\n --bs-modal-header-border-color: var(--bs-border-color);\n --bs-modal-header-border-width: var(--bs-border-width);\n --bs-modal-title-line-height: 1.5;\n --bs-modal-footer-gap: 0.5rem;\n --bs-modal-footer-bg: ;\n --bs-modal-footer-border-color: var(--bs-border-color);\n --bs-modal-footer-border-width: var(--bs-border-width);\n position: fixed;\n top: 0;\n left: 0;\n z-index: var(--bs-modal-zindex);\n display: none;\n width: 100%;\n height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n outline: 0;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: var(--bs-modal-margin);\n pointer-events: none;\n}\n.modal.fade .modal-dialog {\n transition: transform 0.3s ease-out;\n transform: translate(0, -50px);\n}\n@media (prefers-reduced-motion: reduce) {\n .modal.fade .modal-dialog {\n transition: none;\n }\n}\n.modal.show .modal-dialog {\n transform: none;\n}\n.modal.modal-static .modal-dialog {\n transform: scale(1.02);\n}\n\n.modal-dialog-scrollable {\n height: calc(100% - var(--bs-modal-margin) * 2);\n}\n.modal-dialog-scrollable .modal-content {\n max-height: 100%;\n overflow: hidden;\n}\n.modal-dialog-scrollable .modal-body {\n overflow-y: auto;\n}\n\n.modal-dialog-centered {\n display: flex;\n align-items: center;\n min-height: calc(100% - var(--bs-modal-margin) * 2);\n}\n\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n color: var(--bs-modal-color);\n pointer-events: auto;\n background-color: var(--bs-modal-bg);\n background-clip: padding-box;\n border: var(--bs-modal-border-width) solid var(--bs-modal-border-color);\n border-radius: var(--bs-modal-border-radius);\n outline: 0;\n}\n\n.modal-backdrop {\n --bs-backdrop-zindex: 1050;\n --bs-backdrop-bg: #000;\n --bs-backdrop-opacity: 0.5;\n position: fixed;\n top: 0;\n left: 0;\n z-index: var(--bs-backdrop-zindex);\n width: 100vw;\n height: 100vh;\n background-color: var(--bs-backdrop-bg);\n}\n.modal-backdrop.fade {\n opacity: 0;\n}\n.modal-backdrop.show {\n opacity: var(--bs-backdrop-opacity);\n}\n\n.modal-header {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n padding: var(--bs-modal-header-padding);\n border-bottom: var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);\n border-top-left-radius: var(--bs-modal-inner-border-radius);\n border-top-right-radius: var(--bs-modal-inner-border-radius);\n}\n.modal-header .btn-close {\n padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5);\n margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: var(--bs-modal-title-line-height);\n}\n\n.modal-body {\n position: relative;\n flex: 1 1 auto;\n padding: var(--bs-modal-padding);\n}\n\n.modal-footer {\n display: flex;\n flex-shrink: 0;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5);\n background-color: var(--bs-modal-footer-bg);\n border-top: var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);\n border-bottom-right-radius: var(--bs-modal-inner-border-radius);\n border-bottom-left-radius: var(--bs-modal-inner-border-radius);\n}\n.modal-footer > * {\n margin: calc(var(--bs-modal-footer-gap) * 0.5);\n}\n\n@media (min-width: 576px) {\n .modal {\n --bs-modal-margin: 1.75rem;\n --bs-modal-box-shadow: var(--bs-box-shadow);\n }\n .modal-dialog {\n max-width: var(--bs-modal-width);\n margin-right: auto;\n margin-left: auto;\n }\n .modal-sm {\n --bs-modal-width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg,\n .modal-xl {\n --bs-modal-width: 800px;\n }\n}\n@media (min-width: 1200px) {\n .modal-xl {\n --bs-modal-width: 1140px;\n }\n}\n.modal-fullscreen {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n}\n.modal-fullscreen .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n}\n.modal-fullscreen .modal-header,\n.modal-fullscreen .modal-footer {\n border-radius: 0;\n}\n.modal-fullscreen .modal-body {\n overflow-y: auto;\n}\n\n@media (max-width: 575.98px) {\n .modal-fullscreen-sm-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-sm-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-sm-down .modal-header,\n .modal-fullscreen-sm-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-sm-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 767.98px) {\n .modal-fullscreen-md-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-md-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-md-down .modal-header,\n .modal-fullscreen-md-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-md-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 991.98px) {\n .modal-fullscreen-lg-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-lg-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-lg-down .modal-header,\n .modal-fullscreen-lg-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-lg-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 1199.98px) {\n .modal-fullscreen-xl-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-xl-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-xl-down .modal-header,\n .modal-fullscreen-xl-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-xl-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 1399.98px) {\n .modal-fullscreen-xxl-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-xxl-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-xxl-down .modal-header,\n .modal-fullscreen-xxl-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-xxl-down .modal-body {\n overflow-y: auto;\n }\n}\n.tooltip {\n --bs-tooltip-zindex: 1080;\n --bs-tooltip-max-width: 200px;\n --bs-tooltip-padding-x: 0.5rem;\n --bs-tooltip-padding-y: 0.25rem;\n --bs-tooltip-margin: ;\n --bs-tooltip-font-size: 0.875rem;\n --bs-tooltip-color: var(--bs-body-bg);\n --bs-tooltip-bg: var(--bs-emphasis-color);\n --bs-tooltip-border-radius: var(--bs-border-radius);\n --bs-tooltip-opacity: 0.9;\n --bs-tooltip-arrow-width: 0.8rem;\n --bs-tooltip-arrow-height: 0.4rem;\n z-index: var(--bs-tooltip-zindex);\n display: block;\n margin: var(--bs-tooltip-margin);\n font-family: var(--bs-font-sans-serif);\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n white-space: normal;\n word-spacing: normal;\n line-break: auto;\n font-size: var(--bs-tooltip-font-size);\n word-wrap: break-word;\n opacity: 0;\n}\n.tooltip.show {\n opacity: var(--bs-tooltip-opacity);\n}\n.tooltip .tooltip-arrow {\n display: block;\n width: var(--bs-tooltip-arrow-width);\n height: var(--bs-tooltip-arrow-height);\n}\n.tooltip .tooltip-arrow::before {\n position: absolute;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow {\n bottom: calc(-1 * var(--bs-tooltip-arrow-height));\n}\n.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before {\n top: -1px;\n border-width: var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0;\n border-top-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {\n left: calc(-1 * var(--bs-tooltip-arrow-height));\n width: var(--bs-tooltip-arrow-height);\n height: var(--bs-tooltip-arrow-width);\n}\n.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before {\n right: -1px;\n border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0;\n border-right-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:end:ignore */\n.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {\n top: calc(-1 * var(--bs-tooltip-arrow-height));\n}\n.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before {\n bottom: -1px;\n border-width: 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height);\n border-bottom-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {\n right: calc(-1 * var(--bs-tooltip-arrow-height));\n width: var(--bs-tooltip-arrow-height);\n height: var(--bs-tooltip-arrow-width);\n}\n.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before {\n left: -1px;\n border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height);\n border-left-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:end:ignore */\n.tooltip-inner {\n max-width: var(--bs-tooltip-max-width);\n padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);\n color: var(--bs-tooltip-color);\n text-align: center;\n background-color: var(--bs-tooltip-bg);\n border-radius: var(--bs-tooltip-border-radius);\n}\n\n.popover {\n --bs-popover-zindex: 1070;\n --bs-popover-max-width: 276px;\n --bs-popover-font-size: 0.875rem;\n --bs-popover-bg: var(--bs-body-bg);\n --bs-popover-border-width: var(--bs-border-width);\n --bs-popover-border-color: var(--bs-border-color-translucent);\n --bs-popover-border-radius: var(--bs-border-radius-lg);\n --bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));\n --bs-popover-box-shadow: var(--bs-box-shadow);\n --bs-popover-header-padding-x: 1rem;\n --bs-popover-header-padding-y: 0.5rem;\n --bs-popover-header-font-size: 1rem;\n --bs-popover-header-color: inherit;\n --bs-popover-header-bg: var(--bs-secondary-bg);\n --bs-popover-body-padding-x: 1rem;\n --bs-popover-body-padding-y: 1rem;\n --bs-popover-body-color: var(--bs-body-color);\n --bs-popover-arrow-width: 1rem;\n --bs-popover-arrow-height: 0.5rem;\n --bs-popover-arrow-border: var(--bs-popover-border-color);\n z-index: var(--bs-popover-zindex);\n display: block;\n max-width: var(--bs-popover-max-width);\n font-family: var(--bs-font-sans-serif);\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n white-space: normal;\n word-spacing: normal;\n line-break: auto;\n font-size: var(--bs-popover-font-size);\n word-wrap: break-word;\n background-color: var(--bs-popover-bg);\n background-clip: padding-box;\n border: var(--bs-popover-border-width) solid var(--bs-popover-border-color);\n border-radius: var(--bs-popover-border-radius);\n}\n.popover .popover-arrow {\n display: block;\n width: var(--bs-popover-arrow-width);\n height: var(--bs-popover-arrow-height);\n}\n.popover .popover-arrow::before, .popover .popover-arrow::after {\n position: absolute;\n display: block;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n border-width: 0;\n}\n\n.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow {\n bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n}\n.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {\n border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;\n}\n.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before {\n bottom: 0;\n border-top-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {\n bottom: var(--bs-popover-border-width);\n border-top-color: var(--bs-popover-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow {\n left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n width: var(--bs-popover-arrow-height);\n height: var(--bs-popover-arrow-width);\n}\n.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {\n border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;\n}\n.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before {\n left: 0;\n border-right-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {\n left: var(--bs-popover-border-width);\n border-right-color: var(--bs-popover-bg);\n}\n\n/* rtl:end:ignore */\n.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow {\n top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n}\n.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {\n border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);\n}\n.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before {\n top: 0;\n border-bottom-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {\n top: var(--bs-popover-border-width);\n border-bottom-color: var(--bs-popover-bg);\n}\n.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: var(--bs-popover-arrow-width);\n margin-left: calc(-0.5 * var(--bs-popover-arrow-width));\n content: \"\";\n border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow {\n right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n width: var(--bs-popover-arrow-height);\n height: var(--bs-popover-arrow-width);\n}\n.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {\n border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);\n}\n.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before {\n right: 0;\n border-left-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {\n right: var(--bs-popover-border-width);\n border-left-color: var(--bs-popover-bg);\n}\n\n/* rtl:end:ignore */\n.popover-header {\n padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);\n margin-bottom: 0;\n font-size: var(--bs-popover-header-font-size);\n color: var(--bs-popover-header-color);\n background-color: var(--bs-popover-header-bg);\n border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-border-color);\n border-top-left-radius: var(--bs-popover-inner-border-radius);\n border-top-right-radius: var(--bs-popover-inner-border-radius);\n}\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);\n color: var(--bs-popover-body-color);\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel.pointer-event {\n touch-action: pan-y;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.carousel-item {\n position: relative;\n display: none;\n float: left;\n width: 100%;\n margin-right: -100%;\n backface-visibility: hidden;\n transition: transform 0.6s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-item {\n transition: none;\n }\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n.carousel-item-next:not(.carousel-item-start),\n.active.carousel-item-end {\n transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-end),\n.active.carousel-item-start {\n transform: translateX(-100%);\n}\n\n.carousel-fade .carousel-item {\n opacity: 0;\n transition-property: opacity;\n transform: none;\n}\n.carousel-fade .carousel-item.active,\n.carousel-fade .carousel-item-next.carousel-item-start,\n.carousel-fade .carousel-item-prev.carousel-item-end {\n z-index: 1;\n opacity: 1;\n}\n.carousel-fade .active.carousel-item-start,\n.carousel-fade .active.carousel-item-end {\n z-index: 0;\n opacity: 0;\n transition: opacity 0s 0.6s;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-fade .active.carousel-item-start,\n .carousel-fade .active.carousel-item-end {\n transition: none;\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 15%;\n padding: 0;\n color: #fff;\n text-align: center;\n background: none;\n border: 0;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-control-prev,\n .carousel-control-next {\n transition: none;\n }\n}\n.carousel-control-prev:hover, .carousel-control-prev:focus,\n.carousel-control-next:hover,\n.carousel-control-next:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: 0.9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n background-repeat: no-repeat;\n background-position: 50%;\n background-size: 100% 100%;\n}\n\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e\") /*rtl:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\")*/;\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\") /*rtl:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e\")*/;\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 2;\n display: flex;\n justify-content: center;\n padding: 0;\n margin-right: 15%;\n margin-bottom: 1rem;\n margin-left: 15%;\n}\n.carousel-indicators [data-bs-target] {\n box-sizing: content-box;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n padding: 0;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #fff;\n background-clip: padding-box;\n border: 0;\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n opacity: 0.5;\n transition: opacity 0.6s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-indicators [data-bs-target] {\n transition: none;\n }\n}\n.carousel-indicators .active {\n opacity: 1;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 1.25rem;\n left: 15%;\n padding-top: 1.25rem;\n padding-bottom: 1.25rem;\n color: #fff;\n text-align: center;\n}\n\n.carousel-dark .carousel-control-prev-icon,\n.carousel-dark .carousel-control-next-icon {\n filter: invert(1) grayscale(100);\n}\n.carousel-dark .carousel-indicators [data-bs-target] {\n background-color: #000;\n}\n.carousel-dark .carousel-caption {\n color: #000;\n}\n\n[data-bs-theme=dark] .carousel .carousel-control-prev-icon,\n[data-bs-theme=dark] .carousel .carousel-control-next-icon, [data-bs-theme=dark].carousel .carousel-control-prev-icon,\n[data-bs-theme=dark].carousel .carousel-control-next-icon {\n filter: invert(1) grayscale(100);\n}\n[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target], [data-bs-theme=dark].carousel .carousel-indicators [data-bs-target] {\n background-color: #000;\n}\n[data-bs-theme=dark] .carousel .carousel-caption, [data-bs-theme=dark].carousel .carousel-caption {\n color: #000;\n}\n\n.spinner-grow,\n.spinner-border {\n display: inline-block;\n width: var(--bs-spinner-width);\n height: var(--bs-spinner-height);\n vertical-align: var(--bs-spinner-vertical-align);\n border-radius: 50%;\n animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name);\n}\n\n@keyframes spinner-border {\n to {\n transform: rotate(360deg) /* rtl:ignore */;\n }\n}\n.spinner-border {\n --bs-spinner-width: 2rem;\n --bs-spinner-height: 2rem;\n --bs-spinner-vertical-align: -0.125em;\n --bs-spinner-border-width: 0.25em;\n --bs-spinner-animation-speed: 0.75s;\n --bs-spinner-animation-name: spinner-border;\n border: var(--bs-spinner-border-width) solid currentcolor;\n border-right-color: transparent;\n}\n\n.spinner-border-sm {\n --bs-spinner-width: 1rem;\n --bs-spinner-height: 1rem;\n --bs-spinner-border-width: 0.2em;\n}\n\n@keyframes spinner-grow {\n 0% {\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n transform: none;\n }\n}\n.spinner-grow {\n --bs-spinner-width: 2rem;\n --bs-spinner-height: 2rem;\n --bs-spinner-vertical-align: -0.125em;\n --bs-spinner-animation-speed: 0.75s;\n --bs-spinner-animation-name: spinner-grow;\n background-color: currentcolor;\n opacity: 0;\n}\n\n.spinner-grow-sm {\n --bs-spinner-width: 1rem;\n --bs-spinner-height: 1rem;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner-border,\n .spinner-grow {\n --bs-spinner-animation-speed: 1.5s;\n }\n}\n.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm {\n --bs-offcanvas-zindex: 1045;\n --bs-offcanvas-width: 400px;\n --bs-offcanvas-height: 30vh;\n --bs-offcanvas-padding-x: 1rem;\n --bs-offcanvas-padding-y: 1rem;\n --bs-offcanvas-color: var(--bs-body-color);\n --bs-offcanvas-bg: var(--bs-body-bg);\n --bs-offcanvas-border-width: var(--bs-border-width);\n --bs-offcanvas-border-color: var(--bs-border-color-translucent);\n --bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);\n --bs-offcanvas-transition: transform 0.3s ease-in-out;\n --bs-offcanvas-title-line-height: 1.5;\n}\n\n@media (max-width: 575.98px) {\n .offcanvas-sm {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-sm {\n transition: none;\n }\n}\n@media (max-width: 575.98px) {\n .offcanvas-sm.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-sm.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-sm.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-sm.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show {\n visibility: visible;\n }\n}\n@media (min-width: 576px) {\n .offcanvas-sm {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-sm .offcanvas-header {\n display: none;\n }\n .offcanvas-sm .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 767.98px) {\n .offcanvas-md {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-md {\n transition: none;\n }\n}\n@media (max-width: 767.98px) {\n .offcanvas-md.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-md.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-md.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-md.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show {\n visibility: visible;\n }\n}\n@media (min-width: 768px) {\n .offcanvas-md {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-md .offcanvas-header {\n display: none;\n }\n .offcanvas-md .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 991.98px) {\n .offcanvas-lg {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-lg {\n transition: none;\n }\n}\n@media (max-width: 991.98px) {\n .offcanvas-lg.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-lg.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-lg.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-lg.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show {\n visibility: visible;\n }\n}\n@media (min-width: 992px) {\n .offcanvas-lg {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-lg .offcanvas-header {\n display: none;\n }\n .offcanvas-lg .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 1199.98px) {\n .offcanvas-xl {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-xl {\n transition: none;\n }\n}\n@media (max-width: 1199.98px) {\n .offcanvas-xl.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-xl.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-xl.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-xl.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show {\n visibility: visible;\n }\n}\n@media (min-width: 1200px) {\n .offcanvas-xl {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-xl .offcanvas-header {\n display: none;\n }\n .offcanvas-xl .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 1399.98px) {\n .offcanvas-xxl {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-xxl {\n transition: none;\n }\n}\n@media (max-width: 1399.98px) {\n .offcanvas-xxl.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-xxl.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-xxl.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-xxl.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show {\n visibility: visible;\n }\n}\n@media (min-width: 1400px) {\n .offcanvas-xxl {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-xxl .offcanvas-header {\n display: none;\n }\n .offcanvas-xxl .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n.offcanvas {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .offcanvas {\n transition: none;\n }\n}\n.offcanvas.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n}\n.offcanvas.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n}\n.offcanvas.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n}\n.offcanvas.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n}\n.offcanvas.showing, .offcanvas.show:not(.hiding) {\n transform: none;\n}\n.offcanvas.showing, .offcanvas.hiding, .offcanvas.show {\n visibility: visible;\n}\n\n.offcanvas-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1040;\n width: 100vw;\n height: 100vh;\n background-color: #000;\n}\n.offcanvas-backdrop.fade {\n opacity: 0;\n}\n.offcanvas-backdrop.show {\n opacity: 0.5;\n}\n\n.offcanvas-header {\n display: flex;\n align-items: center;\n padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);\n}\n.offcanvas-header .btn-close {\n padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5);\n margin: calc(-0.5 * var(--bs-offcanvas-padding-y)) calc(-0.5 * var(--bs-offcanvas-padding-x)) calc(-0.5 * var(--bs-offcanvas-padding-y)) auto;\n}\n\n.offcanvas-title {\n margin-bottom: 0;\n line-height: var(--bs-offcanvas-title-line-height);\n}\n\n.offcanvas-body {\n flex-grow: 1;\n padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);\n overflow-y: auto;\n}\n\n.placeholder {\n display: inline-block;\n min-height: 1em;\n vertical-align: middle;\n cursor: wait;\n background-color: currentcolor;\n opacity: 0.5;\n}\n.placeholder.btn::before {\n display: inline-block;\n content: \"\";\n}\n\n.placeholder-xs {\n min-height: 0.6em;\n}\n\n.placeholder-sm {\n min-height: 0.8em;\n}\n\n.placeholder-lg {\n min-height: 1.2em;\n}\n\n.placeholder-glow .placeholder {\n animation: placeholder-glow 2s ease-in-out infinite;\n}\n\n@keyframes placeholder-glow {\n 50% {\n opacity: 0.2;\n }\n}\n.placeholder-wave {\n mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\n mask-size: 200% 100%;\n animation: placeholder-wave 2s linear infinite;\n}\n\n@keyframes placeholder-wave {\n 100% {\n mask-position: -200% 0%;\n }\n}\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.text-bg-primary {\n color: #fff !important;\n background-color: RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-secondary {\n color: #fff !important;\n background-color: RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-success {\n color: #fff !important;\n background-color: RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-info {\n color: #000 !important;\n background-color: RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-warning {\n color: #000 !important;\n background-color: RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-danger {\n color: #fff !important;\n background-color: RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-light {\n color: #000 !important;\n background-color: RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-dark {\n color: #fff !important;\n background-color: RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.link-primary {\n color: RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-primary:hover, .link-primary:focus {\n color: RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-secondary {\n color: RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-secondary:hover, .link-secondary:focus {\n color: RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-success {\n color: RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-success:hover, .link-success:focus {\n color: RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-info {\n color: RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-info:hover, .link-info:focus {\n color: RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-warning {\n color: RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-warning:hover, .link-warning:focus {\n color: RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-danger {\n color: RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-danger:hover, .link-danger:focus {\n color: RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-light {\n color: RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-light:hover, .link-light:focus {\n color: RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-dark {\n color: RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-dark:hover, .link-dark:focus {\n color: RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-body-emphasis {\n color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-body-emphasis:hover, .link-body-emphasis:focus {\n color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;\n text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important;\n}\n\n.focus-ring:focus {\n outline: 0;\n box-shadow: var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color);\n}\n\n.icon-link {\n display: inline-flex;\n gap: 0.375rem;\n align-items: center;\n text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));\n text-underline-offset: 0.25em;\n backface-visibility: hidden;\n}\n.icon-link > .bi {\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n fill: currentcolor;\n transition: 0.2s ease-in-out transform;\n}\n@media (prefers-reduced-motion: reduce) {\n .icon-link > .bi {\n transition: none;\n }\n}\n\n.icon-link-hover:hover > .bi, .icon-link-hover:focus-visible > .bi {\n transform: var(--bs-icon-link-transform, translate3d(0.25em, 0, 0));\n}\n\n.ratio {\n position: relative;\n width: 100%;\n}\n.ratio::before {\n display: block;\n padding-top: var(--bs-aspect-ratio);\n content: \"\";\n}\n.ratio > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.ratio-1x1 {\n --bs-aspect-ratio: 100%;\n}\n\n.ratio-4x3 {\n --bs-aspect-ratio: 75%;\n}\n\n.ratio-16x9 {\n --bs-aspect-ratio: 56.25%;\n}\n\n.ratio-21x9 {\n --bs-aspect-ratio: 42.8571428571%;\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n.sticky-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n}\n\n.sticky-bottom {\n position: sticky;\n bottom: 0;\n z-index: 1020;\n}\n\n@media (min-width: 576px) {\n .sticky-sm-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-sm-bottom {\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 768px) {\n .sticky-md-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-md-bottom {\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 992px) {\n .sticky-lg-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-lg-bottom {\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 1200px) {\n .sticky-xl-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-xl-bottom {\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 1400px) {\n .sticky-xxl-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-xxl-bottom {\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n.hstack {\n display: flex;\n flex-direction: row;\n align-items: center;\n align-self: stretch;\n}\n\n.vstack {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n align-self: stretch;\n}\n\n.visually-hidden,\n.visually-hidden-focusable:not(:focus):not(:focus-within) {\n width: 1px !important;\n height: 1px !important;\n padding: 0 !important;\n margin: -1px !important;\n overflow: hidden !important;\n clip: rect(0, 0, 0, 0) !important;\n white-space: nowrap !important;\n border: 0 !important;\n}\n.visually-hidden:not(caption),\n.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {\n position: absolute !important;\n}\n\n.stretched-link::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1;\n content: \"\";\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vr {\n display: inline-block;\n align-self: stretch;\n width: var(--bs-border-width);\n min-height: 1em;\n background-color: currentcolor;\n opacity: 0.25;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.float-start {\n float: left !important;\n}\n\n.float-end {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n.object-fit-contain {\n object-fit: contain !important;\n}\n\n.object-fit-cover {\n object-fit: cover !important;\n}\n\n.object-fit-fill {\n object-fit: fill !important;\n}\n\n.object-fit-scale {\n object-fit: scale-down !important;\n}\n\n.object-fit-none {\n object-fit: none !important;\n}\n\n.opacity-0 {\n opacity: 0 !important;\n}\n\n.opacity-25 {\n opacity: 0.25 !important;\n}\n\n.opacity-50 {\n opacity: 0.5 !important;\n}\n\n.opacity-75 {\n opacity: 0.75 !important;\n}\n\n.opacity-100 {\n opacity: 1 !important;\n}\n\n.overflow-auto {\n overflow: auto !important;\n}\n\n.overflow-hidden {\n overflow: hidden !important;\n}\n\n.overflow-visible {\n overflow: visible !important;\n}\n\n.overflow-scroll {\n overflow: scroll !important;\n}\n\n.overflow-x-auto {\n overflow-x: auto !important;\n}\n\n.overflow-x-hidden {\n overflow-x: hidden !important;\n}\n\n.overflow-x-visible {\n overflow-x: visible !important;\n}\n\n.overflow-x-scroll {\n overflow-x: scroll !important;\n}\n\n.overflow-y-auto {\n overflow-y: auto !important;\n}\n\n.overflow-y-hidden {\n overflow-y: hidden !important;\n}\n\n.overflow-y-visible {\n overflow-y: visible !important;\n}\n\n.overflow-y-scroll {\n overflow-y: scroll !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-inline-grid {\n display: inline-grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.shadow {\n box-shadow: var(--bs-box-shadow) !important;\n}\n\n.shadow-sm {\n box-shadow: var(--bs-box-shadow-sm) !important;\n}\n\n.shadow-lg {\n box-shadow: var(--bs-box-shadow-lg) !important;\n}\n\n.shadow-none {\n box-shadow: none !important;\n}\n\n.focus-ring-primary {\n --bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-secondary {\n --bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-success {\n --bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-info {\n --bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-warning {\n --bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-danger {\n --bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-light {\n --bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-dark {\n --bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity));\n}\n\n.position-static {\n position: static !important;\n}\n\n.position-relative {\n position: relative !important;\n}\n\n.position-absolute {\n position: absolute !important;\n}\n\n.position-fixed {\n position: fixed !important;\n}\n\n.position-sticky {\n position: sticky !important;\n}\n\n.top-0 {\n top: 0 !important;\n}\n\n.top-50 {\n top: 50% !important;\n}\n\n.top-100 {\n top: 100% !important;\n}\n\n.bottom-0 {\n bottom: 0 !important;\n}\n\n.bottom-50 {\n bottom: 50% !important;\n}\n\n.bottom-100 {\n bottom: 100% !important;\n}\n\n.start-0 {\n left: 0 !important;\n}\n\n.start-50 {\n left: 50% !important;\n}\n\n.start-100 {\n left: 100% !important;\n}\n\n.end-0 {\n right: 0 !important;\n}\n\n.end-50 {\n right: 50% !important;\n}\n\n.end-100 {\n right: 100% !important;\n}\n\n.translate-middle {\n transform: translate(-50%, -50%) !important;\n}\n\n.translate-middle-x {\n transform: translateX(-50%) !important;\n}\n\n.translate-middle-y {\n transform: translateY(-50%) !important;\n}\n\n.border {\n border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top {\n border-top: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-end {\n border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-end-0 {\n border-right: 0 !important;\n}\n\n.border-bottom {\n border-bottom: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-start {\n border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-start-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-secondary {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-success {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-info {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-warning {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-danger {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-light {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-dark {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-black {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-white {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-primary-subtle {\n border-color: var(--bs-primary-border-subtle) !important;\n}\n\n.border-secondary-subtle {\n border-color: var(--bs-secondary-border-subtle) !important;\n}\n\n.border-success-subtle {\n border-color: var(--bs-success-border-subtle) !important;\n}\n\n.border-info-subtle {\n border-color: var(--bs-info-border-subtle) !important;\n}\n\n.border-warning-subtle {\n border-color: var(--bs-warning-border-subtle) !important;\n}\n\n.border-danger-subtle {\n border-color: var(--bs-danger-border-subtle) !important;\n}\n\n.border-light-subtle {\n border-color: var(--bs-light-border-subtle) !important;\n}\n\n.border-dark-subtle {\n border-color: var(--bs-dark-border-subtle) !important;\n}\n\n.border-1 {\n border-width: 1px !important;\n}\n\n.border-2 {\n border-width: 2px !important;\n}\n\n.border-3 {\n border-width: 3px !important;\n}\n\n.border-4 {\n border-width: 4px !important;\n}\n\n.border-5 {\n border-width: 5px !important;\n}\n\n.border-opacity-10 {\n --bs-border-opacity: 0.1;\n}\n\n.border-opacity-25 {\n --bs-border-opacity: 0.25;\n}\n\n.border-opacity-50 {\n --bs-border-opacity: 0.5;\n}\n\n.border-opacity-75 {\n --bs-border-opacity: 0.75;\n}\n\n.border-opacity-100 {\n --bs-border-opacity: 1;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.w-auto {\n width: auto !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.vw-100 {\n width: 100vw !important;\n}\n\n.min-vw-100 {\n min-width: 100vw !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.h-auto {\n height: auto !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.vh-100 {\n height: 100vh !important;\n}\n\n.min-vh-100 {\n min-height: 100vh !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-right: 0 !important;\n}\n\n.me-1 {\n margin-right: 0.25rem !important;\n}\n\n.me-2 {\n margin-right: 0.5rem !important;\n}\n\n.me-3 {\n margin-right: 1rem !important;\n}\n\n.me-4 {\n margin-right: 1.5rem !important;\n}\n\n.me-5 {\n margin-right: 3rem !important;\n}\n\n.me-auto {\n margin-right: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-left: 0 !important;\n}\n\n.ms-1 {\n margin-left: 0.25rem !important;\n}\n\n.ms-2 {\n margin-left: 0.5rem !important;\n}\n\n.ms-3 {\n margin-left: 1rem !important;\n}\n\n.ms-4 {\n margin-left: 1.5rem !important;\n}\n\n.ms-5 {\n margin-left: 3rem !important;\n}\n\n.ms-auto {\n margin-left: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-right: 0 !important;\n}\n\n.pe-1 {\n padding-right: 0.25rem !important;\n}\n\n.pe-2 {\n padding-right: 0.5rem !important;\n}\n\n.pe-3 {\n padding-right: 1rem !important;\n}\n\n.pe-4 {\n padding-right: 1.5rem !important;\n}\n\n.pe-5 {\n padding-right: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-left: 0 !important;\n}\n\n.ps-1 {\n padding-left: 0.25rem !important;\n}\n\n.ps-2 {\n padding-left: 0.5rem !important;\n}\n\n.ps-3 {\n padding-left: 1rem !important;\n}\n\n.ps-4 {\n padding-left: 1.5rem !important;\n}\n\n.ps-5 {\n padding-left: 3rem !important;\n}\n\n.gap-0 {\n gap: 0 !important;\n}\n\n.gap-1 {\n gap: 0.25rem !important;\n}\n\n.gap-2 {\n gap: 0.5rem !important;\n}\n\n.gap-3 {\n gap: 1rem !important;\n}\n\n.gap-4 {\n gap: 1.5rem !important;\n}\n\n.gap-5 {\n gap: 3rem !important;\n}\n\n.row-gap-0 {\n row-gap: 0 !important;\n}\n\n.row-gap-1 {\n row-gap: 0.25rem !important;\n}\n\n.row-gap-2 {\n row-gap: 0.5rem !important;\n}\n\n.row-gap-3 {\n row-gap: 1rem !important;\n}\n\n.row-gap-4 {\n row-gap: 1.5rem !important;\n}\n\n.row-gap-5 {\n row-gap: 3rem !important;\n}\n\n.column-gap-0 {\n column-gap: 0 !important;\n}\n\n.column-gap-1 {\n column-gap: 0.25rem !important;\n}\n\n.column-gap-2 {\n column-gap: 0.5rem !important;\n}\n\n.column-gap-3 {\n column-gap: 1rem !important;\n}\n\n.column-gap-4 {\n column-gap: 1.5rem !important;\n}\n\n.column-gap-5 {\n column-gap: 3rem !important;\n}\n\n.font-monospace {\n font-family: var(--bs-font-monospace) !important;\n}\n\n.fs-1 {\n font-size: calc(1.375rem + 1.5vw) !important;\n}\n\n.fs-2 {\n font-size: calc(1.325rem + 0.9vw) !important;\n}\n\n.fs-3 {\n font-size: calc(1.3rem + 0.6vw) !important;\n}\n\n.fs-4 {\n font-size: calc(1.275rem + 0.3vw) !important;\n}\n\n.fs-5 {\n font-size: 1.25rem !important;\n}\n\n.fs-6 {\n font-size: 1rem !important;\n}\n\n.fst-italic {\n font-style: italic !important;\n}\n\n.fst-normal {\n font-style: normal !important;\n}\n\n.fw-lighter {\n font-weight: lighter !important;\n}\n\n.fw-light {\n font-weight: 300 !important;\n}\n\n.fw-normal {\n font-weight: 400 !important;\n}\n\n.fw-medium {\n font-weight: 500 !important;\n}\n\n.fw-semibold {\n font-weight: 600 !important;\n}\n\n.fw-bold {\n font-weight: 700 !important;\n}\n\n.fw-bolder {\n font-weight: bolder !important;\n}\n\n.lh-1 {\n line-height: 1 !important;\n}\n\n.lh-sm {\n line-height: 1.25 !important;\n}\n\n.lh-base {\n line-height: 1.5 !important;\n}\n\n.lh-lg {\n line-height: 2 !important;\n}\n\n.text-start {\n text-align: left !important;\n}\n\n.text-end {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n.text-decoration-none {\n text-decoration: none !important;\n}\n\n.text-decoration-underline {\n text-decoration: underline !important;\n}\n\n.text-decoration-line-through {\n text-decoration: line-through !important;\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.text-wrap {\n white-space: normal !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n/* rtl:begin:remove */\n.text-break {\n word-wrap: break-word !important;\n word-break: break-word !important;\n}\n\n/* rtl:end:remove */\n.text-primary {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-secondary {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-success {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-info {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-warning {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-danger {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-light {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-dark {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-black {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-white {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-body {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-muted {\n --bs-text-opacity: 1;\n color: var(--bs-secondary-color) !important;\n}\n\n.text-black-50 {\n --bs-text-opacity: 1;\n color: rgba(0, 0, 0, 0.5) !important;\n}\n\n.text-white-50 {\n --bs-text-opacity: 1;\n color: rgba(255, 255, 255, 0.5) !important;\n}\n\n.text-body-secondary {\n --bs-text-opacity: 1;\n color: var(--bs-secondary-color) !important;\n}\n\n.text-body-tertiary {\n --bs-text-opacity: 1;\n color: var(--bs-tertiary-color) !important;\n}\n\n.text-body-emphasis {\n --bs-text-opacity: 1;\n color: var(--bs-emphasis-color) !important;\n}\n\n.text-reset {\n --bs-text-opacity: 1;\n color: inherit !important;\n}\n\n.text-opacity-25 {\n --bs-text-opacity: 0.25;\n}\n\n.text-opacity-50 {\n --bs-text-opacity: 0.5;\n}\n\n.text-opacity-75 {\n --bs-text-opacity: 0.75;\n}\n\n.text-opacity-100 {\n --bs-text-opacity: 1;\n}\n\n.text-primary-emphasis {\n color: var(--bs-primary-text-emphasis) !important;\n}\n\n.text-secondary-emphasis {\n color: var(--bs-secondary-text-emphasis) !important;\n}\n\n.text-success-emphasis {\n color: var(--bs-success-text-emphasis) !important;\n}\n\n.text-info-emphasis {\n color: var(--bs-info-text-emphasis) !important;\n}\n\n.text-warning-emphasis {\n color: var(--bs-warning-text-emphasis) !important;\n}\n\n.text-danger-emphasis {\n color: var(--bs-danger-text-emphasis) !important;\n}\n\n.text-light-emphasis {\n color: var(--bs-light-text-emphasis) !important;\n}\n\n.text-dark-emphasis {\n color: var(--bs-dark-text-emphasis) !important;\n}\n\n.link-opacity-10 {\n --bs-link-opacity: 0.1;\n}\n\n.link-opacity-10-hover:hover {\n --bs-link-opacity: 0.1;\n}\n\n.link-opacity-25 {\n --bs-link-opacity: 0.25;\n}\n\n.link-opacity-25-hover:hover {\n --bs-link-opacity: 0.25;\n}\n\n.link-opacity-50 {\n --bs-link-opacity: 0.5;\n}\n\n.link-opacity-50-hover:hover {\n --bs-link-opacity: 0.5;\n}\n\n.link-opacity-75 {\n --bs-link-opacity: 0.75;\n}\n\n.link-opacity-75-hover:hover {\n --bs-link-opacity: 0.75;\n}\n\n.link-opacity-100 {\n --bs-link-opacity: 1;\n}\n\n.link-opacity-100-hover:hover {\n --bs-link-opacity: 1;\n}\n\n.link-offset-1 {\n text-underline-offset: 0.125em !important;\n}\n\n.link-offset-1-hover:hover {\n text-underline-offset: 0.125em !important;\n}\n\n.link-offset-2 {\n text-underline-offset: 0.25em !important;\n}\n\n.link-offset-2-hover:hover {\n text-underline-offset: 0.25em !important;\n}\n\n.link-offset-3 {\n text-underline-offset: 0.375em !important;\n}\n\n.link-offset-3-hover:hover {\n text-underline-offset: 0.375em !important;\n}\n\n.link-underline-primary {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-secondary {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-success {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-info {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-warning {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-danger {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-light {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-dark {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline {\n --bs-link-underline-opacity: 1;\n text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-underline-opacity-0 {\n --bs-link-underline-opacity: 0;\n}\n\n.link-underline-opacity-0-hover:hover {\n --bs-link-underline-opacity: 0;\n}\n\n.link-underline-opacity-10 {\n --bs-link-underline-opacity: 0.1;\n}\n\n.link-underline-opacity-10-hover:hover {\n --bs-link-underline-opacity: 0.1;\n}\n\n.link-underline-opacity-25 {\n --bs-link-underline-opacity: 0.25;\n}\n\n.link-underline-opacity-25-hover:hover {\n --bs-link-underline-opacity: 0.25;\n}\n\n.link-underline-opacity-50 {\n --bs-link-underline-opacity: 0.5;\n}\n\n.link-underline-opacity-50-hover:hover {\n --bs-link-underline-opacity: 0.5;\n}\n\n.link-underline-opacity-75 {\n --bs-link-underline-opacity: 0.75;\n}\n\n.link-underline-opacity-75-hover:hover {\n --bs-link-underline-opacity: 0.75;\n}\n\n.link-underline-opacity-100 {\n --bs-link-underline-opacity: 1;\n}\n\n.link-underline-opacity-100-hover:hover {\n --bs-link-underline-opacity: 1;\n}\n\n.bg-primary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-secondary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-success {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-info {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-warning {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-danger {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-light {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-dark {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-black {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-white {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-body {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-transparent {\n --bs-bg-opacity: 1;\n background-color: transparent !important;\n}\n\n.bg-body-secondary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-body-tertiary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-opacity-10 {\n --bs-bg-opacity: 0.1;\n}\n\n.bg-opacity-25 {\n --bs-bg-opacity: 0.25;\n}\n\n.bg-opacity-50 {\n --bs-bg-opacity: 0.5;\n}\n\n.bg-opacity-75 {\n --bs-bg-opacity: 0.75;\n}\n\n.bg-opacity-100 {\n --bs-bg-opacity: 1;\n}\n\n.bg-primary-subtle {\n background-color: var(--bs-primary-bg-subtle) !important;\n}\n\n.bg-secondary-subtle {\n background-color: var(--bs-secondary-bg-subtle) !important;\n}\n\n.bg-success-subtle {\n background-color: var(--bs-success-bg-subtle) !important;\n}\n\n.bg-info-subtle {\n background-color: var(--bs-info-bg-subtle) !important;\n}\n\n.bg-warning-subtle {\n background-color: var(--bs-warning-bg-subtle) !important;\n}\n\n.bg-danger-subtle {\n background-color: var(--bs-danger-bg-subtle) !important;\n}\n\n.bg-light-subtle {\n background-color: var(--bs-light-bg-subtle) !important;\n}\n\n.bg-dark-subtle {\n background-color: var(--bs-dark-bg-subtle) !important;\n}\n\n.bg-gradient {\n background-image: var(--bs-gradient) !important;\n}\n\n.user-select-all {\n user-select: all !important;\n}\n\n.user-select-auto {\n user-select: auto !important;\n}\n\n.user-select-none {\n user-select: none !important;\n}\n\n.pe-none {\n pointer-events: none !important;\n}\n\n.pe-auto {\n pointer-events: auto !important;\n}\n\n.rounded {\n border-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-0 {\n border-radius: 0 !important;\n}\n\n.rounded-1 {\n border-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-2 {\n border-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-3 {\n border-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-4 {\n border-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-5 {\n border-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-circle {\n border-radius: 50% !important;\n}\n\n.rounded-pill {\n border-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-top {\n border-top-left-radius: var(--bs-border-radius) !important;\n border-top-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-top-0 {\n border-top-left-radius: 0 !important;\n border-top-right-radius: 0 !important;\n}\n\n.rounded-top-1 {\n border-top-left-radius: var(--bs-border-radius-sm) !important;\n border-top-right-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-top-2 {\n border-top-left-radius: var(--bs-border-radius) !important;\n border-top-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-top-3 {\n border-top-left-radius: var(--bs-border-radius-lg) !important;\n border-top-right-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-top-4 {\n border-top-left-radius: var(--bs-border-radius-xl) !important;\n border-top-right-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-top-5 {\n border-top-left-radius: var(--bs-border-radius-xxl) !important;\n border-top-right-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-top-circle {\n border-top-left-radius: 50% !important;\n border-top-right-radius: 50% !important;\n}\n\n.rounded-top-pill {\n border-top-left-radius: var(--bs-border-radius-pill) !important;\n border-top-right-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-end {\n border-top-right-radius: var(--bs-border-radius) !important;\n border-bottom-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-end-0 {\n border-top-right-radius: 0 !important;\n border-bottom-right-radius: 0 !important;\n}\n\n.rounded-end-1 {\n border-top-right-radius: var(--bs-border-radius-sm) !important;\n border-bottom-right-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-end-2 {\n border-top-right-radius: var(--bs-border-radius) !important;\n border-bottom-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-end-3 {\n border-top-right-radius: var(--bs-border-radius-lg) !important;\n border-bottom-right-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-end-4 {\n border-top-right-radius: var(--bs-border-radius-xl) !important;\n border-bottom-right-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-end-5 {\n border-top-right-radius: var(--bs-border-radius-xxl) !important;\n border-bottom-right-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-end-circle {\n border-top-right-radius: 50% !important;\n border-bottom-right-radius: 50% !important;\n}\n\n.rounded-end-pill {\n border-top-right-radius: var(--bs-border-radius-pill) !important;\n border-bottom-right-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: var(--bs-border-radius) !important;\n border-bottom-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-bottom-0 {\n border-bottom-right-radius: 0 !important;\n border-bottom-left-radius: 0 !important;\n}\n\n.rounded-bottom-1 {\n border-bottom-right-radius: var(--bs-border-radius-sm) !important;\n border-bottom-left-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-bottom-2 {\n border-bottom-right-radius: var(--bs-border-radius) !important;\n border-bottom-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-bottom-3 {\n border-bottom-right-radius: var(--bs-border-radius-lg) !important;\n border-bottom-left-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-bottom-4 {\n border-bottom-right-radius: var(--bs-border-radius-xl) !important;\n border-bottom-left-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-bottom-5 {\n border-bottom-right-radius: var(--bs-border-radius-xxl) !important;\n border-bottom-left-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-bottom-circle {\n border-bottom-right-radius: 50% !important;\n border-bottom-left-radius: 50% !important;\n}\n\n.rounded-bottom-pill {\n border-bottom-right-radius: var(--bs-border-radius-pill) !important;\n border-bottom-left-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-start {\n border-bottom-left-radius: var(--bs-border-radius) !important;\n border-top-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-start-0 {\n border-bottom-left-radius: 0 !important;\n border-top-left-radius: 0 !important;\n}\n\n.rounded-start-1 {\n border-bottom-left-radius: var(--bs-border-radius-sm) !important;\n border-top-left-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-start-2 {\n border-bottom-left-radius: var(--bs-border-radius) !important;\n border-top-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-start-3 {\n border-bottom-left-radius: var(--bs-border-radius-lg) !important;\n border-top-left-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-start-4 {\n border-bottom-left-radius: var(--bs-border-radius-xl) !important;\n border-top-left-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-start-5 {\n border-bottom-left-radius: var(--bs-border-radius-xxl) !important;\n border-top-left-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-start-circle {\n border-bottom-left-radius: 50% !important;\n border-top-left-radius: 50% !important;\n}\n\n.rounded-start-pill {\n border-bottom-left-radius: var(--bs-border-radius-pill) !important;\n border-top-left-radius: var(--bs-border-radius-pill) !important;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n.z-n1 {\n z-index: -1 !important;\n}\n\n.z-0 {\n z-index: 0 !important;\n}\n\n.z-1 {\n z-index: 1 !important;\n}\n\n.z-2 {\n z-index: 2 !important;\n}\n\n.z-3 {\n z-index: 3 !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-start {\n float: left !important;\n }\n .float-sm-end {\n float: right !important;\n }\n .float-sm-none {\n float: none !important;\n }\n .object-fit-sm-contain {\n object-fit: contain !important;\n }\n .object-fit-sm-cover {\n object-fit: cover !important;\n }\n .object-fit-sm-fill {\n object-fit: fill !important;\n }\n .object-fit-sm-scale {\n object-fit: scale-down !important;\n }\n .object-fit-sm-none {\n object-fit: none !important;\n }\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-grid {\n display: grid !important;\n }\n .d-sm-inline-grid {\n display: inline-grid !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n .d-sm-none {\n display: none !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n .order-sm-first {\n order: -1 !important;\n }\n .order-sm-0 {\n order: 0 !important;\n }\n .order-sm-1 {\n order: 1 !important;\n }\n .order-sm-2 {\n order: 2 !important;\n }\n .order-sm-3 {\n order: 3 !important;\n }\n .order-sm-4 {\n order: 4 !important;\n }\n .order-sm-5 {\n order: 5 !important;\n }\n .order-sm-last {\n order: 6 !important;\n }\n .m-sm-0 {\n margin: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .me-sm-0 {\n margin-right: 0 !important;\n }\n .me-sm-1 {\n margin-right: 0.25rem !important;\n }\n .me-sm-2 {\n margin-right: 0.5rem !important;\n }\n .me-sm-3 {\n margin-right: 1rem !important;\n }\n .me-sm-4 {\n margin-right: 1.5rem !important;\n }\n .me-sm-5 {\n margin-right: 3rem !important;\n }\n .me-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ms-sm-0 {\n margin-left: 0 !important;\n }\n .ms-sm-1 {\n margin-left: 0.25rem !important;\n }\n .ms-sm-2 {\n margin-left: 0.5rem !important;\n }\n .ms-sm-3 {\n margin-left: 1rem !important;\n }\n .ms-sm-4 {\n margin-left: 1.5rem !important;\n }\n .ms-sm-5 {\n margin-left: 3rem !important;\n }\n .ms-sm-auto {\n margin-left: auto !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pe-sm-0 {\n padding-right: 0 !important;\n }\n .pe-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pe-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pe-sm-3 {\n padding-right: 1rem !important;\n }\n .pe-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pe-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .ps-sm-0 {\n padding-left: 0 !important;\n }\n .ps-sm-1 {\n padding-left: 0.25rem !important;\n }\n .ps-sm-2 {\n padding-left: 0.5rem !important;\n }\n .ps-sm-3 {\n padding-left: 1rem !important;\n }\n .ps-sm-4 {\n padding-left: 1.5rem !important;\n }\n .ps-sm-5 {\n padding-left: 3rem !important;\n }\n .gap-sm-0 {\n gap: 0 !important;\n }\n .gap-sm-1 {\n gap: 0.25rem !important;\n }\n .gap-sm-2 {\n gap: 0.5rem !important;\n }\n .gap-sm-3 {\n gap: 1rem !important;\n }\n .gap-sm-4 {\n gap: 1.5rem !important;\n }\n .gap-sm-5 {\n gap: 3rem !important;\n }\n .row-gap-sm-0 {\n row-gap: 0 !important;\n }\n .row-gap-sm-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-sm-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-sm-3 {\n row-gap: 1rem !important;\n }\n .row-gap-sm-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-sm-5 {\n row-gap: 3rem !important;\n }\n .column-gap-sm-0 {\n column-gap: 0 !important;\n }\n .column-gap-sm-1 {\n column-gap: 0.25rem !important;\n }\n .column-gap-sm-2 {\n column-gap: 0.5rem !important;\n }\n .column-gap-sm-3 {\n column-gap: 1rem !important;\n }\n .column-gap-sm-4 {\n column-gap: 1.5rem !important;\n }\n .column-gap-sm-5 {\n column-gap: 3rem !important;\n }\n .text-sm-start {\n text-align: left !important;\n }\n .text-sm-end {\n text-align: right !important;\n }\n .text-sm-center {\n text-align: center !important;\n }\n}\n@media (min-width: 768px) {\n .float-md-start {\n float: left !important;\n }\n .float-md-end {\n float: right !important;\n }\n .float-md-none {\n float: none !important;\n }\n .object-fit-md-contain {\n object-fit: contain !important;\n }\n .object-fit-md-cover {\n object-fit: cover !important;\n }\n .object-fit-md-fill {\n object-fit: fill !important;\n }\n .object-fit-md-scale {\n object-fit: scale-down !important;\n }\n .object-fit-md-none {\n object-fit: none !important;\n }\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-grid {\n display: grid !important;\n }\n .d-md-inline-grid {\n display: inline-grid !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n .d-md-none {\n display: none !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n .order-md-first {\n order: -1 !important;\n }\n .order-md-0 {\n order: 0 !important;\n }\n .order-md-1 {\n order: 1 !important;\n }\n .order-md-2 {\n order: 2 !important;\n }\n .order-md-3 {\n order: 3 !important;\n }\n .order-md-4 {\n order: 4 !important;\n }\n .order-md-5 {\n order: 5 !important;\n }\n .order-md-last {\n order: 6 !important;\n }\n .m-md-0 {\n margin: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .me-md-0 {\n margin-right: 0 !important;\n }\n .me-md-1 {\n margin-right: 0.25rem !important;\n }\n .me-md-2 {\n margin-right: 0.5rem !important;\n }\n .me-md-3 {\n margin-right: 1rem !important;\n }\n .me-md-4 {\n margin-right: 1.5rem !important;\n }\n .me-md-5 {\n margin-right: 3rem !important;\n }\n .me-md-auto {\n margin-right: auto !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ms-md-0 {\n margin-left: 0 !important;\n }\n .ms-md-1 {\n margin-left: 0.25rem !important;\n }\n .ms-md-2 {\n margin-left: 0.5rem !important;\n }\n .ms-md-3 {\n margin-left: 1rem !important;\n }\n .ms-md-4 {\n margin-left: 1.5rem !important;\n }\n .ms-md-5 {\n margin-left: 3rem !important;\n }\n .ms-md-auto {\n margin-left: auto !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pe-md-0 {\n padding-right: 0 !important;\n }\n .pe-md-1 {\n padding-right: 0.25rem !important;\n }\n .pe-md-2 {\n padding-right: 0.5rem !important;\n }\n .pe-md-3 {\n padding-right: 1rem !important;\n }\n .pe-md-4 {\n padding-right: 1.5rem !important;\n }\n .pe-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .ps-md-0 {\n padding-left: 0 !important;\n }\n .ps-md-1 {\n padding-left: 0.25rem !important;\n }\n .ps-md-2 {\n padding-left: 0.5rem !important;\n }\n .ps-md-3 {\n padding-left: 1rem !important;\n }\n .ps-md-4 {\n padding-left: 1.5rem !important;\n }\n .ps-md-5 {\n padding-left: 3rem !important;\n }\n .gap-md-0 {\n gap: 0 !important;\n }\n .gap-md-1 {\n gap: 0.25rem !important;\n }\n .gap-md-2 {\n gap: 0.5rem !important;\n }\n .gap-md-3 {\n gap: 1rem !important;\n }\n .gap-md-4 {\n gap: 1.5rem !important;\n }\n .gap-md-5 {\n gap: 3rem !important;\n }\n .row-gap-md-0 {\n row-gap: 0 !important;\n }\n .row-gap-md-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-md-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-md-3 {\n row-gap: 1rem !important;\n }\n .row-gap-md-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-md-5 {\n row-gap: 3rem !important;\n }\n .column-gap-md-0 {\n column-gap: 0 !important;\n }\n .column-gap-md-1 {\n column-gap: 0.25rem !important;\n }\n .column-gap-md-2 {\n column-gap: 0.5rem !important;\n }\n .column-gap-md-3 {\n column-gap: 1rem !important;\n }\n .column-gap-md-4 {\n column-gap: 1.5rem !important;\n }\n .column-gap-md-5 {\n column-gap: 3rem !important;\n }\n .text-md-start {\n text-align: left !important;\n }\n .text-md-end {\n text-align: right !important;\n }\n .text-md-center {\n text-align: center !important;\n }\n}\n@media (min-width: 992px) {\n .float-lg-start {\n float: left !important;\n }\n .float-lg-end {\n float: right !important;\n }\n .float-lg-none {\n float: none !important;\n }\n .object-fit-lg-contain {\n object-fit: contain !important;\n }\n .object-fit-lg-cover {\n object-fit: cover !important;\n }\n .object-fit-lg-fill {\n object-fit: fill !important;\n }\n .object-fit-lg-scale {\n object-fit: scale-down !important;\n }\n .object-fit-lg-none {\n object-fit: none !important;\n }\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-grid {\n display: grid !important;\n }\n .d-lg-inline-grid {\n display: inline-grid !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n .d-lg-none {\n display: none !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n .order-lg-first {\n order: -1 !important;\n }\n .order-lg-0 {\n order: 0 !important;\n }\n .order-lg-1 {\n order: 1 !important;\n }\n .order-lg-2 {\n order: 2 !important;\n }\n .order-lg-3 {\n order: 3 !important;\n }\n .order-lg-4 {\n order: 4 !important;\n }\n .order-lg-5 {\n order: 5 !important;\n }\n .order-lg-last {\n order: 6 !important;\n }\n .m-lg-0 {\n margin: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .me-lg-0 {\n margin-right: 0 !important;\n }\n .me-lg-1 {\n margin-right: 0.25rem !important;\n }\n .me-lg-2 {\n margin-right: 0.5rem !important;\n }\n .me-lg-3 {\n margin-right: 1rem !important;\n }\n .me-lg-4 {\n margin-right: 1.5rem !important;\n }\n .me-lg-5 {\n margin-right: 3rem !important;\n }\n .me-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ms-lg-0 {\n margin-left: 0 !important;\n }\n .ms-lg-1 {\n margin-left: 0.25rem !important;\n }\n .ms-lg-2 {\n margin-left: 0.5rem !important;\n }\n .ms-lg-3 {\n margin-left: 1rem !important;\n }\n .ms-lg-4 {\n margin-left: 1.5rem !important;\n }\n .ms-lg-5 {\n margin-left: 3rem !important;\n }\n .ms-lg-auto {\n margin-left: auto !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pe-lg-0 {\n padding-right: 0 !important;\n }\n .pe-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pe-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pe-lg-3 {\n padding-right: 1rem !important;\n }\n .pe-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pe-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .ps-lg-0 {\n padding-left: 0 !important;\n }\n .ps-lg-1 {\n padding-left: 0.25rem !important;\n }\n .ps-lg-2 {\n padding-left: 0.5rem !important;\n }\n .ps-lg-3 {\n padding-left: 1rem !important;\n }\n .ps-lg-4 {\n padding-left: 1.5rem !important;\n }\n .ps-lg-5 {\n padding-left: 3rem !important;\n }\n .gap-lg-0 {\n gap: 0 !important;\n }\n .gap-lg-1 {\n gap: 0.25rem !important;\n }\n .gap-lg-2 {\n gap: 0.5rem !important;\n }\n .gap-lg-3 {\n gap: 1rem !important;\n }\n .gap-lg-4 {\n gap: 1.5rem !important;\n }\n .gap-lg-5 {\n gap: 3rem !important;\n }\n .row-gap-lg-0 {\n row-gap: 0 !important;\n }\n .row-gap-lg-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-lg-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-lg-3 {\n row-gap: 1rem !important;\n }\n .row-gap-lg-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-lg-5 {\n row-gap: 3rem !important;\n }\n .column-gap-lg-0 {\n column-gap: 0 !important;\n }\n .column-gap-lg-1 {\n column-gap: 0.25rem !important;\n }\n .column-gap-lg-2 {\n column-gap: 0.5rem !important;\n }\n .column-gap-lg-3 {\n column-gap: 1rem !important;\n }\n .column-gap-lg-4 {\n column-gap: 1.5rem !important;\n }\n .column-gap-lg-5 {\n column-gap: 3rem !important;\n }\n .text-lg-start {\n text-align: left !important;\n }\n .text-lg-end {\n text-align: right !important;\n }\n .text-lg-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1200px) {\n .float-xl-start {\n float: left !important;\n }\n .float-xl-end {\n float: right !important;\n }\n .float-xl-none {\n float: none !important;\n }\n .object-fit-xl-contain {\n object-fit: contain !important;\n }\n .object-fit-xl-cover {\n object-fit: cover !important;\n }\n .object-fit-xl-fill {\n object-fit: fill !important;\n }\n .object-fit-xl-scale {\n object-fit: scale-down !important;\n }\n .object-fit-xl-none {\n object-fit: none !important;\n }\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-grid {\n display: grid !important;\n }\n .d-xl-inline-grid {\n display: inline-grid !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n .d-xl-none {\n display: none !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n .order-xl-first {\n order: -1 !important;\n }\n .order-xl-0 {\n order: 0 !important;\n }\n .order-xl-1 {\n order: 1 !important;\n }\n .order-xl-2 {\n order: 2 !important;\n }\n .order-xl-3 {\n order: 3 !important;\n }\n .order-xl-4 {\n order: 4 !important;\n }\n .order-xl-5 {\n order: 5 !important;\n }\n .order-xl-last {\n order: 6 !important;\n }\n .m-xl-0 {\n margin: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .me-xl-0 {\n margin-right: 0 !important;\n }\n .me-xl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xl-3 {\n margin-right: 1rem !important;\n }\n .me-xl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xl-5 {\n margin-right: 3rem !important;\n }\n .me-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ms-xl-0 {\n margin-left: 0 !important;\n }\n .ms-xl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xl-3 {\n margin-left: 1rem !important;\n }\n .ms-xl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xl-5 {\n margin-left: 3rem !important;\n }\n .ms-xl-auto {\n margin-left: auto !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pe-xl-0 {\n padding-right: 0 !important;\n }\n .pe-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xl-3 {\n padding-right: 1rem !important;\n }\n .pe-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xl-0 {\n padding-left: 0 !important;\n }\n .ps-xl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xl-3 {\n padding-left: 1rem !important;\n }\n .ps-xl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xl-5 {\n padding-left: 3rem !important;\n }\n .gap-xl-0 {\n gap: 0 !important;\n }\n .gap-xl-1 {\n gap: 0.25rem !important;\n }\n .gap-xl-2 {\n gap: 0.5rem !important;\n }\n .gap-xl-3 {\n gap: 1rem !important;\n }\n .gap-xl-4 {\n gap: 1.5rem !important;\n }\n .gap-xl-5 {\n gap: 3rem !important;\n }\n .row-gap-xl-0 {\n row-gap: 0 !important;\n }\n .row-gap-xl-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-xl-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-xl-3 {\n row-gap: 1rem !important;\n }\n .row-gap-xl-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-xl-5 {\n row-gap: 3rem !important;\n }\n .column-gap-xl-0 {\n column-gap: 0 !important;\n }\n .column-gap-xl-1 {\n column-gap: 0.25rem !important;\n }\n .column-gap-xl-2 {\n column-gap: 0.5rem !important;\n }\n .column-gap-xl-3 {\n column-gap: 1rem !important;\n }\n .column-gap-xl-4 {\n column-gap: 1.5rem !important;\n }\n .column-gap-xl-5 {\n column-gap: 3rem !important;\n }\n .text-xl-start {\n text-align: left !important;\n }\n .text-xl-end {\n text-align: right !important;\n }\n .text-xl-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1400px) {\n .float-xxl-start {\n float: left !important;\n }\n .float-xxl-end {\n float: right !important;\n }\n .float-xxl-none {\n float: none !important;\n }\n .object-fit-xxl-contain {\n object-fit: contain !important;\n }\n .object-fit-xxl-cover {\n object-fit: cover !important;\n }\n .object-fit-xxl-fill {\n object-fit: fill !important;\n }\n .object-fit-xxl-scale {\n object-fit: scale-down !important;\n }\n .object-fit-xxl-none {\n object-fit: none !important;\n }\n .d-xxl-inline {\n display: inline !important;\n }\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n .d-xxl-block {\n display: block !important;\n }\n .d-xxl-grid {\n display: grid !important;\n }\n .d-xxl-inline-grid {\n display: inline-grid !important;\n }\n .d-xxl-table {\n display: table !important;\n }\n .d-xxl-table-row {\n display: table-row !important;\n }\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n .d-xxl-flex {\n display: flex !important;\n }\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n .d-xxl-none {\n display: none !important;\n }\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xxl-row {\n flex-direction: row !important;\n }\n .flex-xxl-column {\n flex-direction: column !important;\n }\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n .align-items-xxl-center {\n align-items: center !important;\n }\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n .align-content-xxl-center {\n align-content: center !important;\n }\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n .align-self-xxl-center {\n align-self: center !important;\n }\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n .order-xxl-first {\n order: -1 !important;\n }\n .order-xxl-0 {\n order: 0 !important;\n }\n .order-xxl-1 {\n order: 1 !important;\n }\n .order-xxl-2 {\n order: 2 !important;\n }\n .order-xxl-3 {\n order: 3 !important;\n }\n .order-xxl-4 {\n order: 4 !important;\n }\n .order-xxl-5 {\n order: 5 !important;\n }\n .order-xxl-last {\n order: 6 !important;\n }\n .m-xxl-0 {\n margin: 0 !important;\n }\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n .m-xxl-3 {\n margin: 1rem !important;\n }\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n .m-xxl-5 {\n margin: 3rem !important;\n }\n .m-xxl-auto {\n margin: auto !important;\n }\n .mx-xxl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xxl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xxl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xxl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xxl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xxl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xxl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n .me-xxl-0 {\n margin-right: 0 !important;\n }\n .me-xxl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xxl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xxl-3 {\n margin-right: 1rem !important;\n }\n .me-xxl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xxl-5 {\n margin-right: 3rem !important;\n }\n .me-xxl-auto {\n margin-right: auto !important;\n }\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n .ms-xxl-0 {\n margin-left: 0 !important;\n }\n .ms-xxl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xxl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xxl-3 {\n margin-left: 1rem !important;\n }\n .ms-xxl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xxl-5 {\n margin-left: 3rem !important;\n }\n .ms-xxl-auto {\n margin-left: auto !important;\n }\n .p-xxl-0 {\n padding: 0 !important;\n }\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n .p-xxl-3 {\n padding: 1rem !important;\n }\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n .p-xxl-5 {\n padding: 3rem !important;\n }\n .px-xxl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xxl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xxl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xxl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xxl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xxl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n .pe-xxl-0 {\n padding-right: 0 !important;\n }\n .pe-xxl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xxl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xxl-3 {\n padding-right: 1rem !important;\n }\n .pe-xxl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xxl-5 {\n padding-right: 3rem !important;\n }\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xxl-0 {\n padding-left: 0 !important;\n }\n .ps-xxl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xxl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xxl-3 {\n padding-left: 1rem !important;\n }\n .ps-xxl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xxl-5 {\n padding-left: 3rem !important;\n }\n .gap-xxl-0 {\n gap: 0 !important;\n }\n .gap-xxl-1 {\n gap: 0.25rem !important;\n }\n .gap-xxl-2 {\n gap: 0.5rem !important;\n }\n .gap-xxl-3 {\n gap: 1rem !important;\n }\n .gap-xxl-4 {\n gap: 1.5rem !important;\n }\n .gap-xxl-5 {\n gap: 3rem !important;\n }\n .row-gap-xxl-0 {\n row-gap: 0 !important;\n }\n .row-gap-xxl-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-xxl-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-xxl-3 {\n row-gap: 1rem !important;\n }\n .row-gap-xxl-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-xxl-5 {\n row-gap: 3rem !important;\n }\n .column-gap-xxl-0 {\n column-gap: 0 !important;\n }\n .column-gap-xxl-1 {\n column-gap: 0.25rem !important;\n }\n .column-gap-xxl-2 {\n column-gap: 0.5rem !important;\n }\n .column-gap-xxl-3 {\n column-gap: 1rem !important;\n }\n .column-gap-xxl-4 {\n column-gap: 1.5rem !important;\n }\n .column-gap-xxl-5 {\n column-gap: 3rem !important;\n }\n .text-xxl-start {\n text-align: left !important;\n }\n .text-xxl-end {\n text-align: right !important;\n }\n .text-xxl-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1200px) {\n .fs-1 {\n font-size: 2.5rem !important;\n }\n .fs-2 {\n font-size: 2rem !important;\n }\n .fs-3 {\n font-size: 1.75rem !important;\n }\n .fs-4 {\n font-size: 1.5rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-grid {\n display: grid !important;\n }\n .d-print-inline-grid {\n display: inline-grid !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n .d-print-none {\n display: none !important;\n }\n}\n\n/*# sourceMappingURL=bootstrap.css.map */\n","@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n",":root,\n[data-bs-theme=\"light\"] {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$prefix}#{$color}-rgb: #{$value};\n }\n\n @each $color, $value in $theme-colors-text {\n --#{$prefix}#{$color}-text-emphasis: #{$value};\n }\n\n @each $color, $value in $theme-colors-bg-subtle {\n --#{$prefix}#{$color}-bg-subtle: #{$value};\n }\n\n @each $color, $value in $theme-colors-border-subtle {\n --#{$prefix}#{$color}-border-subtle: #{$value};\n }\n\n --#{$prefix}white-rgb: #{to-rgb($white)};\n --#{$prefix}black-rgb: #{to-rgb($black)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$prefix}gradient: #{$gradient};\n\n // Root and body\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$prefix}root-font-size: #{$font-size-root};\n }\n --#{$prefix}body-font-family: #{inspect($font-family-base)};\n @include rfs($font-size-base, --#{$prefix}body-font-size);\n --#{$prefix}body-font-weight: #{$font-weight-base};\n --#{$prefix}body-line-height: #{$line-height-base};\n @if $body-text-align != null {\n --#{$prefix}body-text-align: #{$body-text-align};\n }\n\n --#{$prefix}body-color: #{$body-color};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color)};\n --#{$prefix}body-bg: #{$body-bg};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\n\n --#{$prefix}emphasis-color: #{$body-emphasis-color};\n --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};\n\n --#{$prefix}secondary-color: #{$body-secondary-color};\n --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};\n --#{$prefix}secondary-bg: #{$body-secondary-bg};\n --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};\n\n --#{$prefix}tertiary-color: #{$body-tertiary-color};\n --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};\n --#{$prefix}tertiary-bg: #{$body-tertiary-bg};\n --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};\n // scss-docs-end root-body-variables\n\n --#{$prefix}heading-color: #{$headings-color};\n\n --#{$prefix}link-color: #{$link-color};\n --#{$prefix}link-color-rgb: #{to-rgb($link-color)};\n --#{$prefix}link-decoration: #{$link-decoration};\n\n --#{$prefix}link-hover-color: #{$link-hover-color};\n --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};\n\n @if $link-hover-decoration != null {\n --#{$prefix}link-hover-decoration: #{$link-hover-decoration};\n }\n\n --#{$prefix}code-color: #{$code-color};\n --#{$prefix}highlight-color: #{$mark-color};\n --#{$prefix}highlight-bg: #{$mark-bg};\n\n // scss-docs-start root-border-var\n --#{$prefix}border-width: #{$border-width};\n --#{$prefix}border-style: #{$border-style};\n --#{$prefix}border-color: #{$border-color};\n --#{$prefix}border-color-translucent: #{$border-color-translucent};\n\n --#{$prefix}border-radius: #{$border-radius};\n --#{$prefix}border-radius-sm: #{$border-radius-sm};\n --#{$prefix}border-radius-lg: #{$border-radius-lg};\n --#{$prefix}border-radius-xl: #{$border-radius-xl};\n --#{$prefix}border-radius-xxl: #{$border-radius-xxl};\n --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency\n --#{$prefix}border-radius-pill: #{$border-radius-pill};\n // scss-docs-end root-border-var\n\n --#{$prefix}box-shadow: #{$box-shadow};\n --#{$prefix}box-shadow-sm: #{$box-shadow-sm};\n --#{$prefix}box-shadow-lg: #{$box-shadow-lg};\n --#{$prefix}box-shadow-inset: #{$box-shadow-inset};\n\n // Focus styles\n // scss-docs-start root-focus-variables\n --#{$prefix}focus-ring-width: #{$focus-ring-width};\n --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};\n --#{$prefix}focus-ring-color: #{$focus-ring-color};\n // scss-docs-end root-focus-variables\n\n // scss-docs-start root-form-validation-variables\n --#{$prefix}form-valid-color: #{$form-valid-color};\n --#{$prefix}form-valid-border-color: #{$form-valid-border-color};\n --#{$prefix}form-invalid-color: #{$form-invalid-color};\n --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};\n // scss-docs-end root-form-validation-variables\n}\n\n@if $enable-dark-mode {\n @include color-mode(dark, true) {\n color-scheme: dark;\n\n // scss-docs-start root-dark-mode-vars\n --#{$prefix}body-color: #{$body-color-dark};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)};\n --#{$prefix}body-bg: #{$body-bg-dark};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};\n\n --#{$prefix}emphasis-color: #{$body-emphasis-color-dark};\n --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)};\n\n --#{$prefix}secondary-color: #{$body-secondary-color-dark};\n --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};\n --#{$prefix}secondary-bg: #{$body-secondary-bg-dark};\n --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};\n\n --#{$prefix}tertiary-color: #{$body-tertiary-color-dark};\n --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};\n --#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark};\n --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};\n\n @each $color, $value in $theme-colors-text-dark {\n --#{$prefix}#{$color}-text-emphasis: #{$value};\n }\n\n @each $color, $value in $theme-colors-bg-subtle-dark {\n --#{$prefix}#{$color}-bg-subtle: #{$value};\n }\n\n @each $color, $value in $theme-colors-border-subtle-dark {\n --#{$prefix}#{$color}-border-subtle: #{$value};\n }\n\n --#{$prefix}heading-color: #{$headings-color-dark};\n\n --#{$prefix}link-color: #{$link-color-dark};\n --#{$prefix}link-hover-color: #{$link-hover-color-dark};\n --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)};\n --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)};\n\n --#{$prefix}code-color: #{$code-color-dark};\n --#{$prefix}highlight-color: #{$mark-color-dark};\n --#{$prefix}highlight-bg: #{$mark-bg-dark};\n\n --#{$prefix}border-color: #{$border-color-dark};\n --#{$prefix}border-color-translucent: #{$border-color-translucent-dark};\n\n --#{$prefix}form-valid-color: #{$form-valid-color-dark};\n --#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark};\n --#{$prefix}form-invalid-color: #{$form-invalid-color-dark};\n --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark};\n // scss-docs-end root-dark-mode-vars\n }\n}\n","// stylelint-disable scss/dimension-no-non-numeric-values\n\n// SCSS RFS mixin\n//\n// Automated responsive values for font sizes, paddings, margins and much more\n//\n// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)\n\n// Configuration\n\n// Base value\n$rfs-base-value: 1.25rem !default;\n$rfs-unit: rem !default;\n\n@if $rfs-unit != rem and $rfs-unit != px {\n @error \"`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.\";\n}\n\n// Breakpoint at where values start decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n}\n\n// Resize values based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != number or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Mode. Possibilities: \"min-media-query\", \"max-media-query\"\n$rfs-mode: min-media-query !default;\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-rfs to false\n$enable-rfs: true !default;\n\n// Cache $rfs-base-value unit\n$rfs-base-value-unit: unit($rfs-base-value);\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n\n// Remove px-unit from $rfs-base-value for calculations\n@if $rfs-base-value-unit == px {\n $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);\n}\n@else if $rfs-base-value-unit == rem {\n $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == px {\n $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));\n}\n\n// Calculate the media query value\n$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});\n$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);\n$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);\n\n// Internal mixin used to determine which media query needs to be used\n@mixin _rfs-media-query {\n @if $rfs-two-dimensional {\n @if $rfs-mode == max-media-query {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {\n @content;\n }\n }\n}\n\n// Internal mixin that adds disable classes to the selector if needed.\n@mixin _rfs-rule {\n @if $rfs-class == disable and $rfs-mode == max-media-query {\n // Adding an extra class increases specificity, which prevents the media query to override the property\n &,\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @else if $rfs-class == enable and $rfs-mode == min-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Internal mixin that adds enable classes to the selector if needed.\n@mixin _rfs-media-query-rule {\n\n @if $rfs-class == enable {\n @if $rfs-mode == min-media-query {\n @content;\n }\n\n @include _rfs-media-query () {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n }\n @else {\n @if $rfs-class == disable and $rfs-mode == min-media-query {\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @include _rfs-media-query () {\n @content;\n }\n }\n}\n\n// Helper function to get the formatted non-responsive value\n@function rfs-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: \"\";\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + \" 0\";\n }\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n @if $unit == px {\n // Convert to rem if needed\n $val: $val + \" \" + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);\n }\n @else if $unit == rem {\n // Convert to px if needed\n $val: $val + \" \" + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);\n } @else {\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n $val: $val + \" \" + $value;\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// Helper function to get the responsive value calculated by RFS\n@function rfs-fluid-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: \"\";\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + \" 0\";\n } @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $unit or $unit != px and $unit != rem {\n $val: $val + \" \" + $value;\n } @else {\n // Remove unit from $value for calculations\n $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));\n\n // Only add the media query if the value is greater than the minimum value\n @if abs($value) <= $rfs-base-value or not $enable-rfs {\n $val: $val + \" \" + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);\n }\n @else {\n // Calculate the minimum value\n $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);\n\n // Calculate difference between $value and the minimum value\n $value-diff: abs($value) - $value-min;\n\n // Base value formatting\n $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);\n\n // Use negative value if needed\n $min-width: if($value < 0, -$min-width, $min-width);\n\n // Use `vmin` if two-dimensional is enabled\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};\n\n // Return the calculated value\n $val: $val + \" calc(\" + $min-width + if($value < 0, \" - \", \" + \") + $variable-width + \")\";\n }\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// RFS mixin\n@mixin rfs($values, $property: font-size) {\n @if $values != null {\n $val: rfs-value($values);\n $fluid-val: rfs-fluid-value($values);\n\n // Do not print the media query if responsive & non-responsive values are the same\n @if $val == $fluid-val {\n #{$property}: $val;\n }\n @else {\n @include _rfs-rule () {\n #{$property}: if($rfs-mode == max-media-query, $val, $fluid-val);\n\n // Include safari iframe resize fix if needed\n min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);\n }\n\n @include _rfs-media-query-rule () {\n #{$property}: if($rfs-mode == max-media-query, $fluid-val, $val);\n }\n }\n }\n}\n\n// Shorthand helper mixins\n@mixin font-size($value) {\n @include rfs($value);\n}\n\n@mixin padding($value) {\n @include rfs($value, padding);\n}\n\n@mixin padding-top($value) {\n @include rfs($value, padding-top);\n}\n\n@mixin padding-right($value) {\n @include rfs($value, padding-right);\n}\n\n@mixin padding-bottom($value) {\n @include rfs($value, padding-bottom);\n}\n\n@mixin padding-left($value) {\n @include rfs($value, padding-left);\n}\n\n@mixin margin($value) {\n @include rfs($value, margin);\n}\n\n@mixin margin-top($value) {\n @include rfs($value, margin-top);\n}\n\n@mixin margin-right($value) {\n @include rfs($value, margin-right);\n}\n\n@mixin margin-bottom($value) {\n @include rfs($value, margin-bottom);\n}\n\n@mixin margin-left($value) {\n @include rfs($value, margin-left);\n}\n","// scss-docs-start color-mode-mixin\n@mixin color-mode($mode: light, $root: false) {\n @if $color-mode-type == \"media-query\" {\n @if $root == true {\n @media (prefers-color-scheme: $mode) {\n :root {\n @content;\n }\n }\n } @else {\n @media (prefers-color-scheme: $mode) {\n @content;\n }\n }\n } @else {\n [data-bs-theme=\"#{$mode}\"] {\n @content;\n }\n }\n}\n// scss-docs-end color-mode-mixin\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n @include font-size(var(--#{$prefix}root-font-size));\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$prefix}body-font-family);\n @include font-size(var(--#{$prefix}body-font-size));\n font-weight: var(--#{$prefix}body-font-weight);\n line-height: var(--#{$prefix}body-line-height);\n color: var(--#{$prefix}body-color);\n text-align: var(--#{$prefix}body-text-align);\n background-color: var(--#{$prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n border: 0;\n border-top: $hr-border-width solid $hr-border-color;\n opacity: $hr-opacity;\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `

        `-`

        ` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: var(--#{$prefix}heading-color);\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

        `s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 2. Add explicit cursor to indicate changed behavior.\n// 3. Prevent the text-decoration to be skipped.\n\nabbr[title] {\n text-decoration: underline dotted; // 1\n cursor: help; // 2\n text-decoration-skip-ink: none; // 3\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n color: var(--#{$prefix}highlight-color);\n background-color: var(--#{$prefix}highlight-bg);\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));\n text-decoration: $link-decoration;\n\n &:hover {\n --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: var(--#{$prefix}code-color);\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-` +

        +

        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        +
        + + + + + + + + + + diff --git a/views/login-mobile.handlebars b/views/login-mobile.handlebars index 861b92bd..fc38a02e 100644 --- a/views/login-mobile.handlebars +++ b/views/login-mobile.handlebars @@ -63,15 +63,15 @@ - + - + - +
        Username:
        Password:
        @@ -88,9 +88,10 @@ - - + + + @@ -355,6 +356,19 @@ } } + // Display flash error Messages + var flashErrors = JSON.parse('{{{flashErrors}}}'); + if (flashErrors && (flashErrors.length > 0)) { + var msg = ''; + for (i = 0; i < flashErrors.length; i++) { + if (flashErrors[i]) { + msg += '' + flashErrors[i] + '

        '; + } + } + QH('message1', msg); + QV('message1', true); + } + // If URL arguments are provided, add them to form posts if (window.location.href.indexOf('?') > 0) { var urlargs = window.location.href.substring(window.location.href.indexOf('?')); @@ -397,9 +411,10 @@ if (authStrategies.indexOf('twitter') >= 0) { QV('auth-twitter', true); } if (authStrategies.indexOf('google') >= 0) { QV('auth-google', true); } if (authStrategies.indexOf('github') >= 0) { QV('auth-github', true); } - if (authStrategies.indexOf('reddit') >= 0) { QV('auth-reddit', true); } if (authStrategies.indexOf('azure') >= 0) { QV('auth-azure', true); } if (authStrategies.indexOf('oidc') >= 0) { QV('auth-oidc', true); } + if (authStrategies.indexOf('oidc-azure') >= 0) { QV('auth-oidc-azure', true); } + if (authStrategies.indexOf('oidc-google') >= 0) { QV('auth-oidc-google', true); } if (authStrategies.indexOf('jumpcloud') >= 0) { QV('auth-jumpcloud', true); } if (authStrategies.indexOf('intel') >= 0) { QV('auth-intel', true); } if (authStrategies.indexOf('saml') >= 0) { QV('auth-saml', true); } @@ -407,7 +422,6 @@ window.onresize = center; center(); - validateLogin(); validateCreate(); if (loginMode.length != 0) { go(parseInt(loginMode)); } else { go(1); } QV('newAccountDiv', (newAccount === '1') || (newAccount === 'true')); // If new accounts are not allowed, don't display the new account link. @@ -559,13 +573,14 @@ } function validateLogin(box, e) { - var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0)); - QE('loginButton', ok); - setDialogMode(0); - if ((e != null) && (e.keyCode == 13)) { if (box == 1) { Q('password').focus(); } else if (box == 2) { Q('loginButton').click(); } } - if (e != null) { haltEvent(e); } + setTimeout(function(){ + setDialogMode(0); + if ((e != null) && (e.keyCode == 13)) { if (box == 1) { Q('password').focus(); } else if (box == 2) { Q('loginButton').click(); } } + if (e != null) { haltEvent(e); } + }, 100); } + function validateCreate(box,e) { setDialogMode(0); var ok = false; @@ -801,4 +816,4 @@ - \ No newline at end of file + diff --git a/views/login.handlebars b/views/login.handlebars index 7c398df0..2c237789 100644 --- a/views/login.handlebars +++ b/views/login.handlebars @@ -7,6 +7,7 @@ + @@ -54,15 +55,15 @@ - + - + - +
        Username:
        Password:
        @@ -80,9 +81,10 @@ - + + @@ -191,6 +193,7 @@ + @@ -219,6 +222,7 @@ + @@ -335,6 +339,7 @@ var webPageFullScreen = true; var nightMode = (getstore('_nightMode', '0') == '1'); var publicKeyCredentialRequestOptions = null; + var otpduo = (decodeURIComponent('{{{otpduo}}}') === 'true'); var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true'); var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true'); var otpmsg = (decodeURIComponent('{{{otpmsg}}}') === 'true'); @@ -359,6 +364,19 @@ } } + // Display flash error Messages + var flashErrors = JSON.parse('{{{flashErrors}}}'); + if (flashErrors && (flashErrors.length > 0)) { + var msg = ''; + for (i = 0; i < flashErrors.length; i++) { + if (flashErrors[i]) { + msg += '' + flashErrors[i] + '

        '; + } + } + QH('message1', msg); + QV('message1', true); + } + // Fix links if a loginKey if used var urlargs = parseUriArgs(); if (urlargs.key) { @@ -421,9 +439,10 @@ if (authStrategies.indexOf('twitter') >= 0) { QV('auth-twitter', true); } if (authStrategies.indexOf('google') >= 0) { QV('auth-google', true); } if (authStrategies.indexOf('github') >= 0) { QV('auth-github', true); } - if (authStrategies.indexOf('reddit') >= 0) { QV('auth-reddit', true); } if (authStrategies.indexOf('azure') >= 0) { QV('auth-azure', true); } if (authStrategies.indexOf('oidc') >= 0) { QV('auth-oidc', true); } + if (authStrategies.indexOf('oidc-azure') >= 0) { QV('auth-oidc-azure', true); } + if (authStrategies.indexOf('oidc-google') >= 0) { QV('auth-oidc-google', true); } if (authStrategies.indexOf('jumpcloud') >= 0) { QV('auth-jumpcloud', true); } if (authStrategies.indexOf('intel') >= 0) { QV('auth-intel', true); } if (authStrategies.indexOf('saml') >= 0) { QV('auth-saml', true); } @@ -440,7 +459,6 @@ window.onresize = center; center(); - validateLogin(); validateCreate(); if (loginMode.length != 0) { go(parseInt(loginMode)); } else { go(1); } QV('newAccountDiv', (newAccount === '1') || (newAccount === 'true')); // If new accounts are not allowed, don't display the new account link. @@ -459,6 +477,7 @@ QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4) && (messageid != 6)); QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4) && (messageid != 6)); QV('msgKeyButton', otpmsg && (messageid != 2) && (messageid != 4) && (messageid != 6)); + QV('duoKeyButton', otpduo && (messageid != 2) && (messageid != 4) && (messageid != 6)); // If hardware key is an option, trigger it now if (autofido && twofakey) { setTimeout(function () { useSecurityKey(1); }, 300); } @@ -472,6 +491,7 @@ QV('emailKeyButton2', otpemail && (messageid != 2) && (messageid != 4) && (messageid != 6)); QV('smsKeyButton2', otpsms && (messageid != 2) && (messageid != 4) && (messageid != 6)); QV('msgKeyButton2', otpmsg && (messageid != 2) && (messageid != 4) && (messageid != 6)); + QV('duoKeyButton2', otpduo && (messageid != 2) && (messageid != 4) && (messageid != 6)); // If hardware key is an option, trigger it now if (autofido && twofakey) { setTimeout(function () { useSecurityKey(2); }, 300); } @@ -602,6 +622,18 @@ } } + function useDuoToken(panelAction) { + if (panelAction == 1) { + Q('hwtokenInput').value = '**duo**'; + QE('tokenOkButton', true); + Q('tokenOkButton').click(); + } else if (panelAction == 2) { + Q('resetHwtokenInput').value = '**duo**'; + QE('resetTokenOkButton', true); + Q('resetTokenOkButton').click(); + } + } + function showPassHint(e) { messagebox("Password Hint", passhint); haltEvent(e); @@ -646,11 +678,11 @@ } function validateLogin(box, e) { - var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0)); - QE('loginButton', ok); - setDialogMode(0); - if ((e != null) && (e.keyCode == 13)) { if ((box == 1) && (Q('username').value != '')) { Q('password').focus(); } else if ((box == 2) && (Q('password').value != '')) { Q('loginButton').click(); } } - if (e != null) { haltEvent(e); } + setTimeout(function(){ + setDialogMode(0); + if ((e != null) && (e.keyCode == 13)) { if ((box == 1) && (Q('username').value != '')) { Q('password').focus(); } else if ((box == 2) && (Q('password').value != '')) { Q('loginButton').click(); } } + if (e != null) { haltEvent(e); } + }, 100); } function validateCreate(box, e) { @@ -953,4 +985,4 @@ - \ No newline at end of file + diff --git a/views/login2.handlebars b/views/login2.handlebars index 3b44ea17..10537565 100644 --- a/views/login2.handlebars +++ b/views/login2.handlebars @@ -7,6 +7,7 @@ + @@ -68,12 +69,12 @@ @@ -83,9 +84,10 @@ +
        - +
        - +
        - +
        @@ -255,6 +259,7 @@ + @@ -342,6 +347,7 @@
        +
        @@ -389,6 +395,7 @@ var welcomeText = decodeURIComponent('{{{welcometext}}}'); var currentpanel = 0; var publicKeyCredentialRequestOptions = null; + var otpduo = (decodeURIComponent('{{{otpduo}}}') === 'true'); var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true'); var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true'); var otpmsg = (decodeURIComponent('{{{otpmsg}}}') === 'true'); @@ -399,9 +406,13 @@ var tokenTimeout = parseInt('{{{tokenTimeout}}}'); var websocket = null; var formSubmitted = false; + var serverLangs = '{{{renderLanguages}}}'.split(','); + var loclist = { 'af': "Afrikaans", 'sq': "Albanian", 'ar': "Arabic (Standard)", 'ar-dz': "Arabic (Algeria)", 'ar-bh': "Arabic (Bahrain)", 'ar-eg': "Arabic (Egypt)", 'ar-iq': "Arabic (Iraq)", 'ar-jo': "Arabic (Jordan)", 'ar-kw': "Arabic (Kuwait)", 'ar-lb': "Arabic (Lebanon)", 'ar-ly': "Arabic (Libya)", 'ar-ma': "Arabic (Morocco)", 'ar-om': "Arabic (Oman)", 'ar-qa': "Arabic (Qatar)", 'ar-sa': "Arabic (Saudi Arabia)", 'ar-sy': "Arabic (Syria)", 'ar-tn': "Arabic (Tunisia)", 'ar-ae': "Arabic (U.A.E.)", 'ar-ye': "Arabic (Yemen)", 'an': "Aragonese", 'hy': "Armenian", 'as': "Assamese", 'ast': "Asturian", 'az': "Azerbaijani", 'eu': "Basque", 'bg': "Bulgarian", 'be': "Belarusian", 'bn': "Bengali", 'bs': "Bosnian", 'br': "Breton", 'my': "Burmese", 'ca': "Catalan", 'ch': "Chamorro", 'ce': "Chechen", 'zh': "Chinese", 'zh-hk': "Chinese (Hong Kong)", 'zh-cn': "Chinese (PRC)", 'zh-sg': "Chinese (Singapore)", 'zh-tw': "Chinese (Taiwan)", 'cv': "Chuvash", 'co': "Corsican", 'cr': "Cree", 'hr': "Croatian", 'cs': "Czech", 'da': "Danish", 'nl': "Dutch (Standard)", 'nl-be': "Dutch (Belgian)", 'en': "English", 'en-au': "English (Australia)", 'en-bz': "English (Belize)", 'en-ca': "English (Canada)", 'en-ie': "English (Ireland)", 'en-jm': "English (Jamaica)", 'en-nz': "English (New Zealand)", 'en-ph': "English (Philippines)", 'en-za': "English (South Africa)", 'en-tt': "English (Trinidad & Tobago)", 'en-gb': "English (United Kingdom)", 'en-us': "English (United States)", 'en-zw': "English (Zimbabwe)", 'eo': "Esperanto", 'et': "Estonian", 'fo': "Faeroese", 'fa': "Farsi (Persian)", 'fj': "Fijian", 'fi': "Finnish", 'fr': "French (Standard)", 'fr-be': "French (Belgium)", 'fr-ca': "French (Canada)", 'fr-fr': "French (France)", 'fr-lu': "French (Luxembourg)", 'fr-mc': "French (Monaco)", 'fr-ch': "French (Switzerland)", 'fy': "Frisian", 'fur': "Friulian", 'gd': "Gaelic (Scots)", 'gd-ie': "Gaelic (Irish)", 'gl': "Galacian", 'ka': "Georgian", 'de': "German (Standard)", 'de-at': "German (Austria)", 'de-de': "German (Germany)", 'de-li': "German (Liechtenstein)", 'de-lu': "German (Luxembourg)", 'de-ch': "German (Switzerland)", 'el': "Greek", 'gu': "Gujurati", 'ht': "Haitian", 'he': "Hebrew", 'hi': "Hindi", 'hu': "Hungarian", 'is': "Icelandic", 'id': "Indonesian", 'iu': "Inuktitut", 'ga': "Irish", 'it': "Italian (Standard)", 'it-ch': "Italian (Switzerland)", 'ja': "Japanese", 'kn': "Kannada", 'ks': "Kashmiri", 'kk': "Kazakh", 'km': "Khmer", 'ky': "Kirghiz", 'tlh': "Klingon", 'ko': "Korean", 'ko-kp': "Korean (North Korea)", 'ko-kr': "Korean (South Korea)", 'la': "Latin", 'lv': "Latvian", 'lt': "Lithuanian", 'lb': "Luxembourgish", 'mk': "FYRO Macedonian", 'ms': "Malay", 'ml': "Malayalam", 'mt': "Maltese", 'mi': "Maori", 'mr': "Marathi", 'mo': "Moldavian", 'nv': "Navajo", 'ng': "Ndonga", 'ne': "Nepali", 'no': "Norwegian", 'nb': "Norwegian (Bokmal)", 'nn': "Norwegian (Nynorsk)", 'oc': "Occitan", 'or': "Oriya", 'om': "Oromo", 'fa-ir': "Persian/Iran", 'pl': "Polish", 'pt': "Portuguese", 'pt-br': "Portuguese (Brazil)", 'pa': "Punjabi", 'pa-in': "Punjabi (India)", 'pa-pk': "Punjabi (Pakistan)", 'qu': "Quechua", 'rm': "Rhaeto-Romanic", 'ro': "Romanian", 'ro-mo': "Romanian (Moldavia)", 'ru': "Russian", 'ru-mo': "Russian (Moldavia)", 'sz': "Sami (Lappish)", 'sg': "Sango", 'sa': "Sanskrit", 'sc': "Sardinian", 'sd': "Sindhi", 'si': "Singhalese", 'sr': "Serbian", 'sk': "Slovak", 'sl': "Slovenian", 'so': "Somani", 'sb': "Sorbian", 'es': "Spanish", 'es-ar': "Spanish (Argentina)", 'es-bo': "Spanish (Bolivia)", 'es-cl': "Spanish (Chile)", 'es-co': "Spanish (Colombia)", 'es-cr': "Spanish (Costa Rica)", 'es-do': "Spanish (Dominican Republic)", 'es-ec': "Spanish (Ecuador)", 'es-sv': "Spanish (El Salvador)", 'es-gt': "Spanish (Guatemala)", 'es-hn': "Spanish (Honduras)", 'es-mx': "Spanish (Mexico)", 'es-ni': "Spanish (Nicaragua)", 'es-pa': "Spanish (Panama)", 'es-py': "Spanish (Paraguay)", 'es-pe': "Spanish (Peru)", 'es-pr': "Spanish (Puerto Rico)", 'es-es': "Spanish (Spain)", 'es-uy': "Spanish (Uruguay)", 'es-ve': "Spanish (Venezuela)", 'sx': "Sutu", 'sw': "Swahili", 'sv': "Swedish", 'sv-fi': "Swedish (Finland)", 'sv-sv': "Swedish (Sweden)", 'ta': "Tamil", 'tt': "Tatar", 'te': "Teluga", 'th': "Thai", 'tig': "Tigre", 'ts': "Tsonga", 'tn': "Tswana", 'tr': "Turkish", 'tk': "Turkmen", 'uk': "Ukrainian", 'hsb': "Upper Sorbian", 'ur': "Urdu", 've': "Venda", 'vi': "Vietnamese", 'vo': "Volapuk", 'wa': "Walloon", 'cy': "Welsh", 'xh': "Xhosa", 'ji': "Yiddish", 'zu': "Zulu" }; + var loclistex = { 'zh-chs': "Chinese (Simplified)", 'zh-cht': "Chinese (Traditional)" }; + var showLanguageSelect = '{{{showLanguageSelect}}}'; function startup() { - if (decodeURIComponent('{{{loginpicture}}}') == 'true') { Q('loginPicture').src = "loginlogo.png"; } + if (decodeURIComponent('{{{loginpicture}}}') == 'true') { Q('loginPicture').src = 'loginlogo.png'; } QV('welcomeTextRow', welcomeText != ''); QH('welcomeText', welcomeText); @@ -429,10 +440,36 @@ } } + // Display flash error Messages + var flashErrors = JSON.parse('{{{flashErrors}}}'); + if (flashErrors && (flashErrors.length > 0)) { + var msg = ''; + for (i = 0; i < flashErrors.length; i++) { + if (flashErrors[i]) { + msg += '' + flashErrors[i] + '

        '; + } + } + QH('message1', msg); + QV('message1', true); + } + // Fix links if a loginKey if used var urlargs = parseUriArgs(); //if (urlargs.key) { Q('termsLinkFooter').href += '?key=' + urlargs.key; } + // Show Language Select Box if needed + if (showLanguageSelect === 'top' || showLanguageSelect === 'bottom') { + var x = ' +
        - -   + +    
        @@ -217,6 +217,13 @@
        +
        + + + + + +

        Agent Remote Desktop

        @@ -340,6 +347,16 @@ setupTerminal(); setupFiles(); + // Set the file editor + d4EditWrapVal = Number(getstore('editorWrap', 0)); + d4EditSizeVal = Number(getstore('editorSize', 0)); + d4EditEncodingVal = Number(getstore('editorEncoding', 0)); + d4EditLineBreakVal = Number(getstore('editorLineBreak', 0)); + d4ToggleWrap(true); + d4ToggleSize(true); + d4ToggleEncoding(true); + d4ToggleLineBreak(true); + // Set the document title if (nodeName.length > 0) { document.title += ' - ' + nodeName; } @@ -393,7 +410,7 @@ } function deskAdjust() { - if ((xxcurrentView == 12) && (terminal != null) && (xtermfit != null)) { xtermfit.fit(); } // Terminal + if ((xxcurrentView == 12) && (terminal != null) && (xtermfit != null)) { xtermfit.fit(); } // Terminal QS('fileArea4')['height'] = 'calc(100vh - ' + (90 + Q('fileArea2').clientHeight) + 'px)'; // Files var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth; var deskH = Q('Desk').height, deskW = Q('Desk').width; @@ -480,6 +497,9 @@ QE('DeskWD', deskState == 3); QV('deskkeys', viewOnly != 1); QE('deskkeys', deskState == 3); + QV('DeskTimer', deskState == 3); + QV('DeskLatency', deskState == 3); + QS('DeskLatency').display = (deskState == 3 ? 'inline-block' : 'none'); // Display this only if we have Chat & Notify permissions QV('DeskSaveImageButton', (deskState == 3) && (Q('Desk')['toBlob'] != null)); @@ -536,7 +556,7 @@ } else if ((data.action == 'present') && (webRtcDesktop == null)) { // Setup WebRTC channel webRtcDesktop = { platform: data.platform }; - var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] }; + var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.cloudflare.com:3478' }, { 'urls': 'stun:stun.l.google.com:19302' } ] }; if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); } else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); } @@ -624,7 +644,7 @@ desktop.m.onDisplayinfo = deskDisplayInfo; desktop.m.onScreenSizeChange = deskAdjust; desktop.Start(null); - desktop.latency.callback = function (ms) { console.log('latency', ms); updateSessionTime(); }; + desktop.latency.callback = function (ms) { /* console.log('latency', ms); */ updateSessionTime(); }; desktop.contype = 1; } } else { @@ -736,14 +756,26 @@ // Desktop var latencyStr = '', seconds = 0; if (desktop && desktop.startTime) { - if (desktop.latency && (desktop.latency.current >= 0)) { latencyStr = format('{0} ms, ', desktop.latency.current); } + if (desktop.latency && (desktop.latency.current >= 0)) { latencyStr = format('{0} ms', desktop.latency.current); } seconds = Math.floor((new Date() - desktop.startTime) / 1000); - QH('DeskTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2)); + QH('DeskTimer', zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2)); + QH('DeskLatency', latencyStr); } else { QH('DeskTimer', ''); + QH('DeskLatency', ''); } - if (desktop == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; } + // Terminal + seconds = 0; + if (terminal && terminal.startTime) { + if (terminal.latency && (terminal.latency.current >= 0)) { latencyStr = format('{0} ms, ', terminal.latency.current); } + seconds = Math.floor((new Date() - terminal.startTime) / 1000); + QH('TermTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2)); + } else { + QH('TermTimer', ''); + } + + if ((desktop == null) && (terminal == null)) { clearInterval(updateSessionTimer); updateSessionTimer = null; } } function showDesktopSettings() { @@ -797,6 +829,7 @@ // Enter browser fullscreen function enterBrowserFullscreen(elem) { + if (navigator.keyboard && navigator.keyboard.lock) { navigator.keyboard.lock(); } if (elem.requestFullscreen) { elem.requestFullscreen(); } else if (elem.msRequestFullscreen) { elem.msRequestFullscreen(); } else if (elem.mozRequestFullScreen) { elem.mozRequestFullScreen(); } @@ -809,6 +842,7 @@ else if (document.msExitFullscreen) { document.msExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } + if (navigator.keyboard && navigator.keyboard.unlock) { navigator.keyboard.unlock(); } } // Return true if the browser is fullscreen. This is a delayed method that will return true/false late. Not very useful. @@ -888,6 +922,7 @@ // Remote desktop special key combos for Windows function deskSendKeys() { + Q('DeskWD').blur(); if (xxdialogMode || desktop == null || desktop.State != 3) return; var ks = Q('deskkeys').value; if (ks == 0) { // WIN+Down arrow @@ -1373,20 +1408,6 @@ updateTerminalButtons(); } - function updateSessionTime() { - // Terminal - var latencyStr = '', seconds = 0; - if (terminal && terminal.startTime) { - if (terminal.latency && (terminal.latency.current >= 0)) { latencyStr = format('{0} ms, ', terminal.latency.current); } - seconds = Math.floor((new Date() - terminal.startTime) / 1000); - QH('TermTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2)); - } else { - QH('TermTimer', ''); - } - - if (terminal == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; } - } - // DEBUG var autoConnectTerminalTimer = null; function autoConnectTerminal(e) { if (autoConnectTerminalTimer == null) { autoConnectTerminalTimer = setInterval(connectTerminal, 100); } else { clearInterval(autoConnectTerminalTimer); autoConnectTerminalTimer = null; } } @@ -1405,7 +1426,13 @@ return obj; } - function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } } + function tunnelUpdate(data) { + if (xterm.writeUtf8) { + if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } + } else { + if (typeof data == 'string') { xterm.write(data); } else { xterm.write(new Uint8Array(data)); } + } + } // Send the new terminal size to the agent function xTermSendResize() { @@ -1567,7 +1594,7 @@ // // Files - // + // function setupFiles() { // Setup the files tab @@ -1902,7 +1929,7 @@ function p13zipFiles() { var inputFiles = [], checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { inputFiles.push(p13filetree.dir[checkboxes[i].value].n); } } - setDialogMode(2, "Zip Filename", 3, p13zipFilesEx, '', { action: 'zip', path: p13filetreelocation.join('/'), files: inputFiles }); + setDialogMode(2, "Zip Filename", 3, p13zipFilesEx, '', { action: 'zip -r', path: p13filetreelocation.join('/'), files: inputFiles }); focusTextBox('p13renameinput'); p13fileNameCheck(); } @@ -2020,6 +2047,8 @@ if (gdownloadFile.tag == 'viewer') { // View the file in the dialog box setDialogMode(4, EscapeHtml(gdownloadFile.file), 3, p13editSaveBack, null, gdownloadFile.file); + QV('d4EncodingButton', true); + QV('d4LineBreakButton', true); QS('dialog').width = 'auto'; QS('dialog').bottom = '80px'; QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px'; @@ -2036,6 +2065,9 @@ var d4EditWrapVal = 0; var d4EditSizeVal = 0; + var d4EditEncodingVal = 0; + var d4EditLineBreakVal = 0; + function d4ToggleWrap(update) { if (!update) { d4EditWrapVal = ++d4EditWrapVal % 2; } Q('d4WrapButton').value = ["Wrap: ON", "Wrap: OFF"][d4EditWrapVal]; @@ -2051,8 +2083,38 @@ putstore('editorSize', d4EditSizeVal); } + function d4ToggleEncoding(update) { + if (!update) { + d4EditEncodingVal = ++d4EditEncodingVal % 2; + if (d4EditEncodingVal == 1) { + Q('d4editorarea').value = decode_utf8(Q('d4editorarea').value); + } else { + Q('d4editorarea').value = encode_utf8(Q('d4editorarea').value); + } + } + Q('d4EncodingButton').value = ["Encoding: RAW","Encoding: UTF8"][d4EditEncodingVal]; + putstore('editorEncoding', d4EditEncodingVal); + } + + function d4ToggleLineBreak(update) { + if (!update) { + d4EditLineBreakVal = ++d4EditLineBreakVal % 3; + } + Q('d4LineBreakButton').value = ["Line Break: Windows (CR LF)","Line Break: Linux (LF)","Line Break: Mac (CR)"][d4EditLineBreakVal]; + putstore('editorLineBreak', d4EditLineBreakVal); + } + function p13editSaveBack(b, tag) { - var data = new TextEncoder().encode(Q('d4editorarea').value); + var data; + var value = Q('d4editorarea').value; + value = d4EditLineBreakVal === 0 ? value.replace(/\r?\n|\r/g, '\r\n') : // Windows + d4EditLineBreakVal === 2 ? value.replace(/\r\n|\n/g, '\r') : // Mac + value.replace(/\r\n|\r/g, '\n'); // Linux + if (d4EditEncodingVal == 1) { + data = new TextEncoder().encode(value); // UTF8 encoding + } else { + data = new TextEncoder().encode(decode_utf8(value)); // RAW encoding + } p13uploadFileContinue(1, [{ name: tag, size: data.byteLength, type: 'text/plain', xdata: data }]); } @@ -2183,7 +2245,7 @@ if (start >= data.byteLength) { files.sendText(JSON.stringify({ action: 'uploaddone', reqid: uploadFile.xfilePtr })); } else { - var end = uploadFile.xptr + 16384; + var end = uploadFile.xptr + 65536; if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; } var dataslice = new Uint8Array(data.slice(start, end)) if ((dataslice[0] == 123) || (dataslice[0] == 0)) { @@ -2250,6 +2312,27 @@ xxcurrentView = x; } + function putstore(name, val) { + try { + if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; + if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } + } catch (ex) { } + if (name[0] != '_') { + var s = {}; + try { + for (var i = 0, len = localStorage.length; i < len; ++i) { + var k = localStorage.key(i); + if (k[0] != '_') { + s[k] = localStorage.getItem(k); + if ((k != 'desktopsettings') && (k != 'stars') && (k != 'deskKeyShortcuts') && (k != 'deskStrings') && (k != 'cmdopt') && (typeof s[k] == 'string') && (s[k].length > 64)) { delete s[k]; } + } + } + } catch (ex) {} + // meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); + } + } + + function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } } function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); } function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); } function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; } @@ -2283,4 +2366,4 @@ start(); - \ No newline at end of file + diff --git a/views/xterm.handlebars b/views/xterm.handlebars index 21e41028..380b115e 100644 --- a/views/xterm.handlebars +++ b/views/xterm.handlebars @@ -181,10 +181,10 @@ } function tunnelUpdate(data) { - if (typeof data == 'string') { - term.writeUtf8(data); + if (term.writeUtf8) { + if (typeof data == 'string') { term.writeUtf8(data); } else { term.writeUtf8(new Uint8Array(data)); } } else { - term.writeUtf8(new Uint8Array(data)); + if (typeof data == 'string') { term.write(data); } else { term.write(new Uint8Array(data)); } } } diff --git a/webrelayserver.js b/webrelayserver.js index a7a967ae..66ab2761 100644 --- a/webrelayserver.js +++ b/webrelayserver.js @@ -86,6 +86,19 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates, } if (args.sessiontime != null) { sessionOptions.maxAge = (args.sessiontime * 60000); } // sessiontime is minutes obj.app.use(require('cookie-session')(sessionOptions)); + obj.app.use(function(request, response, next) { // Patch for passport 0.6.0 - https://github.com/jaredhanson/passport/issues/904 + if (request.session && !request.session.regenerate) { + request.session.regenerate = function (cb) { + cb() + } + } + if (request.session && !request.session.save) { + request.session.save = function (cb) { + cb() + } + } + next() + }); // Add HTTP security headers to all responses obj.app.use(function (req, res, next) { diff --git a/webserver.js b/webserver.js index 5219c169..9a93d5a2 100644 --- a/webserver.js +++ b/webserver.js @@ -51,7 +51,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF obj.meshIderHandler = require('./amt/amt-ider.js'); obj.meshUserHandler = require('./meshuser.js'); obj.interceptor = require('./interceptor'); - obj.uaparser = require('./ua-parser'); + obj.uaparser = require('ua-parser-js'); const constants = (obj.crypto.constants ? obj.crypto.constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead. // Setup WebAuthn / FIDO2 @@ -72,6 +72,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF obj.users = {}; // UserID --> User obj.meshes = {}; // MeshID --> Mesh (also called device group) obj.userGroups = {}; // UGrpID --> User Group + obj.useNodeDefaultTLSCiphers = args.usenodedefaulttlsciphers; // Use TLS ciphers provided by node + obj.tlsCiphers = args.tlsciphers; // List of TLS ciphers to use obj.userAllowedIp = args.userallowedip; // List of allowed IP addresses for users obj.agentAllowedIp = args.agentallowedip; // List of allowed IP addresses for agents obj.agentBlockedIp = args.agentblockedip; // List of blocked IP addresses for agents @@ -151,7 +153,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF obj.webCertificateHashBase64 = Buffer.from(obj.webCertificateHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); obj.webCertificateFullHash = parent.certificateOperations.getCertHashBinary(obj.certificates.web.cert); obj.webCertificateFullHashs = { '': obj.webCertificateFullHash }; - obj.webCertificateExpire = { '': Date.parse(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.web.cert).validity.notAfter) }; + obj.webCertificateExpire = { '': parent.certificateOperations.getCertificateExpire(parent.certificates.web.cert) }; obj.agentCertificateHashHex = parent.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert); obj.agentCertificateHashBase64 = Buffer.from(obj.agentCertificateHashHex, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); obj.agentCertificateAsn1 = parent.certificateOperations.forge.asn1.toDer(parent.certificateOperations.forge.pki.certificateToAsn1(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.agent.cert))).getBytes(); @@ -457,7 +459,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Save this LDAP user to file if needed if (typeof domain.ldapsaveusertofile == 'string') { - obj.fs.appendFile(domain.ldapsaveusertofile, JSON.stringify(xxuser, null, 2) + '\r\n\r\n', function (err) { }); + obj.fs.appendFile(domain.ldapsaveusertofile, JSON.stringify(xxuser) + '\r\n\r\n', function (err) { }); } // Work on getting the userid for this LDAP user @@ -489,17 +491,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (Array.isArray(userMemberships) == false) { userMemberships = []; } // See if the user is required to be part of an LDAP user group in order to log into this server. - if (typeof domain.ldapuserrequiredgroupmembership == 'string') { domain.ldapuserrequiredgroupmembership = [ domain.ldapuserrequiredgroupmembership ]; } + if (typeof domain.ldapuserrequiredgroupmembership == 'string') { domain.ldapuserrequiredgroupmembership = [domain.ldapuserrequiredgroupmembership]; } if (Array.isArray(domain.ldapuserrequiredgroupmembership)) { // Look for a matching LDAP user group var userMembershipMatch = false; for (var i in domain.ldapuserrequiredgroupmembership) { if (userMemberships.indexOf(domain.ldapuserrequiredgroupmembership[i]) >= 0) { userMembershipMatch = true; } } - if (userMembershipMatch === false) { parent.debug('authlog', 'LDAP denying login to a user that is not a member of a LDAP required group.'); fn('denied'); return; } // If there is no match, deny the login + if (userMembershipMatch === false) { parent.authLog('ldapHandler', 'LDAP denying login to a user that is not a member of a LDAP required group.'); fn('denied'); return; } // If there is no match, deny the login } // Check if user is in an site administrator group var siteAdminGroup = null; - if (typeof domain.ldapsiteadmingroups == 'string') { domain.ldapsiteadmingroups = [ domain.ldapsiteadmingroups ]; } + if (typeof domain.ldapsiteadmingroups == 'string') { domain.ldapsiteadmingroups = [domain.ldapsiteadmingroups]; } if (Array.isArray(domain.ldapsiteadmingroups)) { siteAdminGroup = false; for (var i in domain.ldapsiteadmingroups) { @@ -559,7 +561,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } // Display user information extracted from LDAP data - parent.debug('authlog', 'LDAP user login, id: ' + shortname + ', username: ' + username + ', email: ' + email + ', realname: ' + realname + ', phone: ' + phonenumber + ', image: ' + (userimage != null)); + parent.authLog('ldapHandler', 'LDAP user login, id: ' + shortname + ', username: ' + username + ', email: ' + email + ', realname: ' + realname + ', phone: ' + phonenumber + ', image: ' + (userimage != null)); // If there is a testing userid, use that if (ldapHandlerFunc.ldapShortName) { @@ -619,7 +621,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // See if the user is a member of the site admin group. if (typeof siteAdminGroup === 'string') { - parent.debug('authlog', `LDAP: Granting site admin privilages to new user "${user.name}" found in admin group: ${siteAdminGroup}`); + parent.authLog('ldapHandler', `LDAP: Granting site admin privilages to new user "${user.name}" found in admin group: ${siteAdminGroup}`); user.siteadmin = 0xFFFFFFFF; } @@ -662,11 +664,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // See if the user is a member of the site admin group. if ((typeof siteAdminGroup === 'string') && (user.siteadmin !== 0xFFFFFFFF)) { - parent.debug('authlog', `LDAP: Granting site admin privilages to user "${user.name}" found in administrator group: ${siteAdminGroup}`); + parent.authLog('ldapHandler', `LDAP: Granting site admin privilages to user "${user.name}" found in administrator group: ${siteAdminGroup}`); user.siteadmin = 0xFFFFFFFF; userChanged = true; } else if ((siteAdminGroup === false) && (user.siteadmin === 0xFFFFFFFF)) { - parent.debug('authlog', `LDAP: Revoking site admin privilages from user "${user.name}" since they are not found in any administrator groups.`); + parent.authLog('ldapHandler', `LDAP: Revoking site admin privilages from user "${user.name}" since they are not found in any administrator groups.`); delete user.siteadmin; userChanged = true; } @@ -836,21 +838,30 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF parent.debug('web', 'handleLogoutRequest: success.'); // If this user was logged in using an authentication strategy and there is a logout URL, use it. - if ((userid != null) && (domain.authstrategies != null)) { - const u = userid.split('/')[2]; - if (u.startsWith('~twitter:') && (domain.authstrategies.twitter != null) && (typeof domain.authstrategies.twitter.logouturl == 'string')) { res.redirect(domain.authstrategies.twitter.logouturl); return; } - if (u.startsWith('~google:') && (domain.authstrategies.google != null) && (typeof domain.authstrategies.google.logouturl == 'string')) { res.redirect(domain.authstrategies.google.logouturl); return; } - if (u.startsWith('~github:') && (domain.authstrategies.github != null) && (typeof domain.authstrategies.github.logouturl == 'string')) { res.redirect(domain.authstrategies.github.logouturl); return; } - if (u.startsWith('~reddit:') && (domain.authstrategies.reddit != null) && (typeof domain.authstrategies.reddit.logouturl == 'string')) { res.redirect(domain.authstrategies.reddit.logouturl); return; } - if (u.startsWith('~azure:') && (domain.authstrategies.azure != null) && (typeof domain.authstrategies.azure.logouturl == 'string')) { res.redirect(domain.authstrategies.azure.logouturl); return; } - if (u.startsWith('~oidc:') && (domain.authstrategies.oidc != null) && (typeof domain.authstrategies.oidc.logouturl == 'string')) { res.redirect(domain.authstrategies.oidc.logouturl); return; } - if (u.startsWith('~jumpcloud:') && (domain.authstrategies.jumpcloud != null) && (typeof domain.authstrategies.jumpcloud.logouturl == 'string')) { res.redirect(domain.authstrategies.jumpcloud.logouturl); return; } - if (u.startsWith('~saml:') && (domain.authstrategies.saml != null) && (typeof domain.authstrategies.saml.logouturl == 'string')) { res.redirect(domain.authstrategies.saml.logouturl); return; } - if (u.startsWith('~intel:') && (domain.authstrategies.intel != null) && (typeof domain.authstrategies.intel.logouturl == 'string')) { res.redirect(domain.authstrategies.intel.logouturl); return; } + if ((userid != null) && (domain.authstrategies?.authStrategyFlags != null)) { + let logouturl = null; + let userStrategy = ((userid.split('/')[2]).split(':')[0]).substring(1); + // Setup logout url for oidc + if (userStrategy == 'oidc' && domain.authstrategies.oidc != null) { + if (typeof domain.authstrategies.oidc.logouturl == 'string') { + logouturl = domain.authstrategies.oidc.logouturl; + } else if (typeof domain.authstrategies.oidc.issuer.end_session_endpoint == 'string' && typeof domain.authstrategies.oidc.client.post_logout_redirect_uri == 'string') { + logouturl = domain.authstrategies.oidc.issuer.end_session_endpoint + '?post_logout_redirect_uri=' + domain.authstrategies.oidc.client.post_logout_redirect_uri; + } else if (typeof domain.authstrategies.oidc.issuer.end_session_endpoint == 'string') { + logouturl = domain.authstrategies.oidc.issuer.end_session_endpoint; + } + // Log out all other strategies + } else if ((domain.authstrategies[userStrategy] != null) && (typeof domain.authstrategies[userStrategy].logouturl == 'string')) { logouturl = domain.authstrategies[userStrategy].logouturl; } + // If custom logout was setup, use it + if (logouturl != null) { + parent.authLog('handleLogoutRequest', userStrategy.toUpperCase() + ': LOGOUT: ' + logouturl); + res.redirect(logouturl); + return; + } } // This is the default logout redirect to the login page - if (req.query.key != null) { res.redirect(domain.url + 'login?key=' + req.query.key); } else { res.redirect(domain.url + 'login'); } + if (req.query.key != null) { res.redirect(domain.url + 'login?key=' + encodeURIComponent(req.query.key)); } else { res.redirect(domain.url + 'login'); } } // Return an object with 2FA type if 2-step auth can be skipped @@ -907,7 +918,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null)); // Check if a 2nd factor is present - return ((parent.config.settings.no2factorauth !== true) && (msg2fa || sms2fa || (user.otpsecret != null) || ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) || ((user.otphkeys != null) && (user.otphkeys.length > 0)))); + return ((parent.config.settings.no2factorauth !== true) && (msg2fa || sms2fa || (user.otpsecret != null) || ((user.email != null) && (user.emailVerified == true) && (domain.mailserver != null) && (user.otpekey != null)) || (user.otpduo != null) || ((user.otphkeys != null) && (user.otphkeys.length > 0)))); } // Check the 2-step auth token @@ -1151,6 +1162,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var sms2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.sms2factor != false)) && (parent.smsserver != null) && (user.phone != null)); var msg2fa = (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false)) && (parent.msgserver != null) && (parent.msgserver.providers != 0) && (user.msghandle != null)); var push2fa = ((parent.firebase != null) && (user.otpdev != null)); + var duo2fa = ((((typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) || ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.duo2factor != false))) && (user.otpduo != null)); // Check if two factor can be skipped const twoFactorSkip = checkUserOneTimePasswordSkip(domain, user, req, loginOptions); @@ -1200,6 +1212,24 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF return; } + if ((req.body.hwtoken == '**duo**') && duo2fa && (typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) { + // Redirect to duo here + const duo = require('@duosecurity/duo_universal'); + const client = new duo.Client({ + clientId: domain.duo2factor.integrationkey, + clientSecret: domain.duo2factor.secretkey, + apiHost: domain.duo2factor.apihostname, + redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('?key=' + domain.loginkey) : '') + }); + // Decrypt any session data + const sec = parent.decryptSessionData(req.session.e); + sec.duostate = client.generateState(); + req.session.e = parent.encryptSessionData(sec); + parent.debug('web', 'Redirecting user ' + user._id + ' to Duo'); + res.redirect(client.createAuthUrl(user._id.split('/')[2], sec.duostate)); + return; + } + // Handle device push notification 2FA request // We create a browser cookie, send it back and when the browser connects it's web socket, it will trigger the push notification. if ((req.body.hwtoken == '**push**') && push2fa && ((domain.passwordrequirements == null) || (domain.passwordrequirements.push2factor != false))) { @@ -1263,6 +1293,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((user.phone != null) && (parent.smsserver != null)) { req.session.tsms = 1; } if ((user.msghandle != null) && (parent.msgserver != null) && (parent.msgserver.providers != 0)) { req.session.tmsg = 1; } if ((user.otpdev != null) && (parent.firebase != null)) { req.session.tpush = 1; } + if ((user.otpduo != null)) { req.session.tduo = 1; } req.session.e = parent.encryptSessionData({ tuserid: userid, tuser: xusername, tpass: xpassword }); if (direct === true) { handleRootRequestEx(req, res, domain); } else { res.redirect(domain.url + getQueryPortion(req)); } }, randomWaitTime); @@ -1411,7 +1442,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF req.session.userid = userid; req.session.ip = req.clientIp; setSessionRandom(req); - obj.parent.authLog('https', 'Accepted password for ' + xusername + ' from ' + req.clientIp + ' port ' + req.connection.remotePort, { useragent: req.headers['user-agent'], sessionid: req.session.x }); + obj.parent.authLog('https', 'Accepted password for ' + (xusername ? xusername : userid) + ' from ' + req.clientIp + ' port ' + req.connection.remotePort, { useragent: req.headers['user-agent'], sessionid: req.session.x }); // If a login token was used, add this information and expire time to the session. if ((loginOptions != null) && (loginOptions.tokenName != null) && (loginOptions.tokenUser != null)) { @@ -1958,28 +1989,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var idsplit = cookie.u.split('/'); if ((idsplit.length != 3) || (idsplit[1] != domain.id)) { parent.debug('web', 'handleCheckMailRequest: Invalid domain.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } else { obj.db.Get(cookie.u, function (err, docs) { if (docs.length == 0) { parent.debug('web', 'handleCheckMailRequest: Invalid username.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(idsplit[1]).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(idsplit[1]).replace(/'/g, '%27') }, req, domain)); } else { var user = docs[0]; if (user.email != cookie.e) { parent.debug('web', 'handleCheckMailRequest: Invalid e-mail.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 3, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 3, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain)); } else { if (cookie.a == 1) { // Account email verification if (user.emailVerified == true) { parent.debug('web', 'handleCheckMailRequest: email already verified.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 4, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 4, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain)); } else { obj.db.GetUserWithVerifiedEmail(domain.id, user.email, function (err, docs) { if ((docs.length > 0) && (docs.find(function (u) { return (u._id === user._id); }) < 0)) { parent.debug('web', 'handleCheckMailRequest: email already in use.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 5, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 5, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27') }, req, domain)); } else { parent.debug('web', 'handleCheckMailRequest: email verification success.'); @@ -1994,12 +2025,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event); // Send the confirmation page - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 6, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 6, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain)); // Send a notification obj.parent.DispatchEvent([user._id], obj, { action: 'notify', title: 'Email verified', value: user.email, nolog: 1, id: Math.random() }); - // Send to authlog + // Send to authLog obj.parent.authLog('https', 'Verified email address ' + user.email + ' for user ' + user.name, { useragent: req.headers['user-agent'] }); } }); @@ -2008,7 +2039,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Account reset if (user.emailVerified != true) { parent.debug('web', 'handleCheckMailRequest: email not verified.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 7, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.email), arg2: EscapeHtml(user.name) }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 7, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.email), arg2: EscapeHtml(user.name) }, req, domain)); } else { if (req.query.confirm == 1) { // Set a temporary password @@ -2032,28 +2063,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event); // Send the new password - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 8, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.name), arg2: EscapeHtml(newpass) }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 8, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.name), arg2: EscapeHtml(newpass) }, req, domain)); parent.debug('web', 'handleCheckMailRequest: send temporary password.'); - // Send to authlog + // Send to authLog obj.parent.authLog('https', 'Performed account reset for user ' + user.name); }, 0); }); } else { // Display a link for the user to confirm password reset // We must do this because GMail will also load this URL a few seconds after the user does and we don't want to cause two password resets. - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 14, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 14, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } } } else { - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } } } }); } } else { - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 10, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 1, msgid: 10, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } } } @@ -2062,6 +2093,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF function handleInviteRequest(req, res) { const domain = getDomain(req); if (domain == null) { parent.debug('web', 'handleInviteRequest: failed checks.'); res.sendStatus(404); return; } + if (domain.agentinvitecodes != true) { nice404(req, res); return; } if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key if ((req.body == null) || (req.body.inviteCode == null) || (req.body.inviteCode == '')) { render(req, res, getRenderPage('invite', req, domain), getRenderArgs({ messageid: 0 }, req, domain)); return; } // No invitation code @@ -2069,7 +2101,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF for (var i in obj.meshes) { if ((obj.meshes[i].domain == domain.id) && (obj.meshes[i].deleted == null) && (obj.meshes[i].invite != null) && (obj.meshes[i].invite.codes.indexOf(req.body.inviteCode) >= 0)) { // Send invitation link, valid for 1 minute. - res.redirect(domain.url + 'agentinvite?c=' + parent.encodeCookie({ a: 4, mid: i, f: obj.meshes[i].invite.flags, ag: obj.meshes[i].invite.ag, expire: 1 }, parent.invitationLinkEncryptionKey) + (req.query.key ? ('&key=' + req.query.key) : '') + (req.query.hide ? ('&hide=' + req.query.hide) : '')); + res.redirect(domain.url + 'agentinvite?c=' + parent.encodeCookie({ a: 4, mid: i, f: obj.meshes[i].invite.flags, ag: obj.meshes[i].invite.ag, expire: 1 }, parent.invitationLinkEncryptionKey) + (req.query.key ? ('&key=' + encodeURIComponent(req.query.key)) : '') + (req.query.hide ? ('&hide=' + encodeURIComponent(req.query.hide)) : '')); return; } } @@ -2085,7 +2117,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Check if we are in maintenance mode if ((parent.config.settings.maintenancemode != null) && (req.query.loginscreen !== '1')) { - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 3, msgid: 13, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 3, msgid: 13, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } @@ -2093,35 +2125,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var features = 0; if (domain.allowsavingdevicecredentials === false) { features |= 1; } - if (req.query.ws != null) { - // This is a query with a websocket relay cookie, check that the cookie is valid and use it. - var rcookie = parent.decodeCookie(req.query.ws, parent.loginCookieEncryptionKey, 60); // Cookie with 1 hour timeout - if ((rcookie != null) && (rcookie.domainid == domain.id) && (rcookie.nodeid != null) && (rcookie.tcpport != null)) { - - // Fetch the node from the database - obj.db.Get(rcookie.nodeid, function (err, nodes) { - if ((err != null) || (nodes.length != 1)) { res.sendStatus(404); return; } - const node = nodes[0]; - - // Check if we have SSH/RDP credentials for this device - var serverCredentials = 0; - if (domain.allowsavingdevicecredentials !== false) { - if (page == 'ssh') { - if ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string') && (typeof node.ssh.p == 'string')) { serverCredentials = 1; } // Username and password - else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string') && (typeof node.ssh.kp == 'string')) { serverCredentials = 2; } // Username, key and password - else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string')) { serverCredentials = 3; } // Username and key. No password. - } else { - if ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { serverCredentials = 1; } // Username and password - } - } - - // Render the page - render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: req.query.ws, name: encodeURIComponent(req.query.name).replace(/'/g, '%27'), serverCredentials: serverCredentials, features: features }, req, domain)); - }); - return; - } - } - // Get the logged in user if present var user = null; @@ -2140,6 +2143,39 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // No user login, exit now if (user == null) { res.sendStatus(401); return; } + if (req.query.ws != null) { + // This is a query with a websocket relay cookie, check that the cookie is valid and use it. + var rcookie = parent.decodeCookie(req.query.ws, parent.loginCookieEncryptionKey, 60); // Cookie with 1 hour timeout + if ((rcookie != null) && (rcookie.domainid == domain.id) && (rcookie.nodeid != null) && (rcookie.tcpport != null)) { + + // Fetch the node from the database + obj.db.Get(rcookie.nodeid, function (err, nodes) { + if ((err != null) || (nodes.length != 1)) { res.sendStatus(404); return; } + const node = nodes[0]; + + // Check if we have SSH/RDP credentials for this device + var serverCredentials = 0; + if (domain.allowsavingdevicecredentials !== false) { + if (page == 'ssh') { + if ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string') && (typeof node.ssh.p == 'string')) { serverCredentials = 1; } // Username and password + else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string') && (typeof node.ssh.kp == 'string')) { serverCredentials = 2; } // Username, key and password + else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string')) { serverCredentials = 3; } // Username and key. No password. + else if ((typeof node.ssh == 'object') && (typeof node.ssh[user._id] == 'object') && (typeof node.ssh[user._id].u == 'string') && (typeof node.ssh[user._id].p == 'string')) { serverCredentials = 1; } // Username and password in per user format + else if ((typeof node.ssh == 'object') && (typeof node.ssh[user._id] == 'object') && (typeof node.ssh[user._id].k == 'string') && (typeof node.ssh[user._id].kp == 'string')) { serverCredentials = 2; } // Username, key and password in per user format + else if ((typeof node.ssh == 'object') && (typeof node.ssh[user._id] == 'object') && (typeof node.ssh[user._id].k == 'string')) { serverCredentials = 3; } // Username and key. No password. in per user format + } else { + if ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { serverCredentials = 1; } // Username and password in legacy format + if ((typeof node.rdp == 'object') && (typeof node.rdp[user._id] == 'object') && (typeof node.rdp[user._id].d == 'string') && (typeof node.rdp[user._id].u == 'string') && (typeof node.rdp[user._id].p == 'string')) { serverCredentials = 1; } // Username and password in per user format + } + } + + // Render the page + render(req, res, getRenderPage(page, req, domain), getRenderArgs({ cookie: req.query.ws, name: encodeURIComponent(req.query.name).replace(/'/g, '%27'), serverCredentials: serverCredentials, features: features }, req, domain)); + }); + return; + } + } + // Check the nodeid if (req.query.node != null) { var nodeidsplit = req.query.node.split('/'); @@ -2175,6 +2211,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((typeof node.ssh == 'object') && (typeof node.ssh.u == 'string') && (typeof node.ssh.p == 'string')) { serverCredentials = 1; } // Username and password else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string') && (typeof node.ssh.kp == 'string')) { serverCredentials = 2; } // Username, key and password else if ((typeof node.ssh == 'object') && (typeof node.ssh.k == 'string')) { serverCredentials = 3; } // Username and key. No password. + else if ((typeof node.ssh == 'object') && (typeof node.ssh[user._id] == 'object') && (typeof node.ssh[user._id].u == 'string') && (typeof node.ssh[user._id].p == 'string')) { serverCredentials = 1; } // Username and password in per user format + else if ((typeof node.ssh == 'object') && (typeof node.ssh[user._id] == 'object') && (typeof node.ssh[user._id].k == 'string') && (typeof node.ssh[user._id].kp == 'string')) { serverCredentials = 2; } // Username, key and password in per user format + else if ((typeof node.ssh == 'object') && (typeof node.ssh[user._id] == 'object') && (typeof node.ssh[user._id].k == 'string')) { serverCredentials = 3; } // Username and key. No password. in per user format } } else { // RDP port @@ -2184,6 +2223,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Check if we have RDP credentials for this device if (domain.allowsavingdevicecredentials !== false) { if ((typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { serverCredentials = 1; } // Username and password + if ((typeof node.rdp == 'object') && (typeof node.rdp[user._id] == 'object') && (typeof node.rdp[user._id].d == 'string') && (typeof node.rdp[user._id].u == 'string') && (typeof node.rdp[user._id].p == 'string')) { serverCredentials = 1; } // Username and password in per user format } } if (req.query.port != null) { var qport = 0; try { qport = parseInt(req.query.port); } catch (ex) { } if ((typeof qport == 'number') && (qport > 0) && (qport < 65536)) { port = qport; } } @@ -2255,7 +2295,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var magenturl = 'mc://' + agentServerName + ((agentHttpsPort != 443) ? (':' + agentHttpsPort) : '') + ((xdomain != '') ? ('/' + xdomain) : '') + ',' + obj.agentCertificateHashBase64 + ',' + mesh._id.split('/')[2]; var meshcookie = parent.encodeCookie({ m: mesh._id.split('/')[2] }, parent.invitationLinkEncryptionKey); - render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: 1, servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags, showagents: showagents, magenturl: magenturl }, req, domain)); + render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: 1, servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags, showagents: showagents, magenturl: magenturl, assistanttype: (domain.assistanttypeagentinvite ? domain.assistanttypeagentinvite : 0) }, req, domain)); } else if (req.query.m != null) { // The MeshId is specified in the query string, use that var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.m.toLowerCase()]; @@ -2278,7 +2318,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var magenturl = 'mc://' + agentServerName + ((agentHttpsPort != 443) ? (':' + agentHttpsPort) : '') + ((xdomain != '') ? ('/' + xdomain) : '') + ',' + obj.agentCertificateHashBase64 + ',' + mesh._id.split('/')[2]; var meshcookie = parent.encodeCookie({ m: mesh._id.split('/')[2] }, parent.invitationLinkEncryptionKey); - render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: 1, servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags, showagents: showagents, magenturl: magenturl }, req, domain)); + render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: 1, servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags, showagents: showagents, magenturl: magenturl, assistanttype: (domain.assistanttypeagentinvite ? domain.assistanttypeagentinvite : 0) }, req, domain)); } } @@ -2575,61 +2615,79 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF const domain = checkUserIpAddress(req, res); if (domain == null) { return; } if ((req.user != null) && (req.user.sid != null) && (req.user.strategy != null)) { - const authStrategy = req.user.strategy - parent.debug('authlog', `${authStrategy.toUpperCase()}: Verified user: ${JSON.stringify(req.user, null, 4)}` + JSON.stringify(req.user)); + const strategy = domain.authstrategies[req.user.strategy]; + const groups = { 'enabled': typeof strategy.groups == 'object' } + parent.authLog(req.user.strategy.toUpperCase(), `User Authorized: ${JSON.stringify(req.user)}`); + if (groups.enabled) { // Groups only available for OIDC strategy currently + groups.userMemberships = obj.common.convertStrArray(req.user.groups); + groups.syncEnabled = (strategy.groups.sync === true || strategy.groups.sync?.filter) ? true : false; + groups.syncMemberships = []; + groups.siteAdminEnabled = strategy.groups.siteadmin ? true : false; + groups.grantAdmin = false; + groups.revokeAdmin = strategy.groups.revokeAdmin ? strategy.groups.revokeAdmin : true; + groups.requiredGroups = obj.common.convertStrArray(strategy.groups.required); + groups.siteAdmin = obj.common.convertStrArray(strategy.groups.siteadmin); + groups.syncFilter = obj.common.convertStrArray(strategy.groups.sync?.filter); - // Check if any group related options exist - var userMemberships = []; - var siteAdminGroup = null; - if (typeof domain.authstrategies[authStrategy].groups === 'object') { - if (Array.isArray(req.user.groups)) { userMemberships = req.user.groups; } - else if (typeof req.user.groups == 'string') { userMemberships = [req.user.groups]; } - parent.debug('authlog', `${authStrategy.toUpperCase()}: Member Of: ${userMemberships.join(', ')}`); + // Fancy Logs + let groupMessage = ''; + if (groups.userMemberships.length == 1) { groupMessage = ` Found membership: "${groups.userMemberships[0]}"` } + else { groupMessage = ` Found ${groups.userMemberships.length} memberships: ["${groups.userMemberships.join('", "')}"]` } + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}"` + groupMessage); - // See if the user is required to be part of a specific group in order to log into this server. - if (typeof domain.authstrategies[authStrategy].groups.required == 'string') { domain.authstrategies[authStrategy].groups.required = [domain.authstrategies[authStrategy].groups.required]; } - if (Array.isArray(domain.authstrategies[authStrategy].groups.required)) { - var userMembershipMatch = false; - for (var i in domain.authstrategies[authStrategy].groups.required) { - if (userMemberships.indexOf(domain.authstrategies[authStrategy].groups.required[i]) >= 0) { - userMembershipMatch = true; - parent.debug('authlog', `${authStrategy.toUpperCase()}: ${req.user.name} is member of required group: ${domain.authstrategies[authStrategy].groups.required[i]}`); + // Check user membership in required groups + if (groups.requiredGroups.length > 0) { + let match = false + for (var i in groups.requiredGroups) { + if (groups.userMemberships.indexOf(groups.requiredGroups[i]) != -1) { + match = true; + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" Membership to required group found: "${groups.requiredGroups[i]}"`); } } - if (userMembershipMatch === false) { - parent.debug('authlog', `${authStrategy}: User login denied. User not found in required group.`); + if (match === false) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" Login denied. No membership to required group.`); req.session.loginmode = 1; - req.session.messageid = 100; // Unable to create account. + req.session.messageid = 111; // Access Denied. res.redirect(domain.url + getQueryPortion(req)); return; } } - // Check if user is in an administrator group - if (typeof domain.authstrategies[authStrategy].groups.siteadmin == 'string') { domain.authstrategies[authStrategy].groups.siteadmin = [ domain.authstrategies[authStrategy].groups.siteadmin ]; } - if (Array.isArray(domain.authstrategies[authStrategy].groups.siteadmin)) { - siteAdminGroup = false; - for (var i in domain.authstrategies[authStrategy].groups.siteadmin) { - if (userMemberships.indexOf(domain.authstrategies[authStrategy].groups.siteadmin[i]) >= 0) { siteAdminGroup = domain.authstrategies[authStrategy].groups.siteadmin[i]; } + // Check user membership in admin groups + if (groups.siteAdminEnabled === true) { + groups.grantAdmin = false; + for (var i in strategy.groups.siteadmin) { + if (groups.userMemberships.indexOf(strategy.groups.siteadmin[i]) >= 0) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" User membership found in site admin group: "${strategy.groups.siteadmin[i]}"`); + groups.siteAdmin = strategy.groups.siteadmin[i]; + groups.grantAdmin = true; + break; + } } } - // See if we need to sync user-memberships (IdP) with user-groups (meshcentral) - if (domain.authstrategies[authStrategy].groups.sync === true) { domain.authstrategies[authStrategy].groups.sync = { enabled: true }; } - if (typeof domain.authstrategies[authStrategy].groups.sync.filter == 'string' || Array.isArray(domain.authstrategies[authStrategy].groups.sync.filter)) { - if (typeof domain.authstrategies[authStrategy].groups.sync.filter == 'string') { domain.authstrategies[authStrategy].groups.sync.filter = [ domain.authstrategies[authStrategy].groups.sync.filter ]; } - const filteredMemberships = []; - for (var i in userMemberships) { - for (var j in domain.authstrategies[authStrategy].groups.sync.filter) { - if (userMemberships[i].indexOf(domain.authstrategies[authStrategy].groups.sync.filter[j]) >= 0) { filteredMemberships.push(userMemberships[i]); } + // Check if we need to sync user-memberships (IdP) with user-groups (meshcentral) + if (groups.syncEnabled === true) { + if (groups.syncFilter.length > 0){ // config.json has specified sync.filter so loop and use it + for (var i in groups.syncFilter) { + if (groups.userMemberships.indexOf(groups.syncFilter[i]) >= 0) { groups.syncMemberships.push(groups.syncFilter[i]); } + } + } else { // config.json doesnt have sync.filter specified so we are going to sync all the users groups from oidc instead + for (var i in groups.userMemberships) { + groups.syncMemberships.push(groups.userMemberships[i]); } } - if (filteredMemberships.length > 0) { - parent.debug('authlog', `${authStrategy.toUpperCase()}: Filtered user memberships from config: ${filteredMemberships.join(', ')}`); - } else { - parent.debug('authlog', `${authStrategy.toUpperCase()}: No groups found with filter: ${domain.authstrategies[authStrategy].groups.sync.filter.join(', ')}`); + if (groups.syncMemberships.length > 0) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" User memberships to sync: ${groups.syncMemberships.join(', ')}`); + } else { + groups.syncMemberships = null; + groups.syncEnabled = false; + if (groups.syncFilter.length > 0){ + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" No sync memberships found using filters: ${groups.syncFilter.join(', ')}`); + } else { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" No sync memberships found`); + } } - userMemberships = filteredMemberships; } } @@ -2643,25 +2701,25 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (domain.newaccounts === true) { newAccountAllowed = true; } if (obj.common.validateStrArray(domain.newaccountrealms)) { newAccountRealms = domain.newaccountrealms; } - if ((domain.authstrategies != null) && (domain.authstrategies[authStrategy] != null)) { - if (domain.authstrategies[authStrategy].newaccounts === true) { newAccountAllowed = true; } - if (obj.common.validateStrArray(domain.authstrategies[authStrategy].newaccountrealms)) { newAccountRealms = domain.authstrategies[req.user.strategy].newaccountrealms; } + if (domain.authstrategies[req.user.strategy]) { + if (domain.authstrategies[req.user.strategy].newaccounts === true) { newAccountAllowed = true; } + if (obj.common.validateStrArray(domain.authstrategies[req.user.strategy].newaccountrealms)) { newAccountRealms = domain.authstrategies[req.user.strategy].newaccountrealms; } } if (newAccountAllowed === true) { // Create the user - parent.debug('authlog', `${authStrategy.toUpperCase()}: Creating new login user: "${userid}"`); + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: USER: "${req.user.sid}" Creating new login user: "${userid}"`); user = { type: 'user', _id: userid, name: req.user.name, email: req.user.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), access: Math.floor(Date.now() / 1000), domain: domain.id }; - if (req.user.email != null) { user.email = req.user.email; user.emailVerified = true; } + if (req.user.email != null) { user.email = req.user.email; user.emailVerified = req.user.email_verified ? req.user.email_verified : true; } if (domain.newaccountsrights) { user.siteadmin = domain.newaccountsrights; } // New accounts automatically assigned server rights. - if (domain.authstrategies[authStrategy].newaccountsrights) { user.siteadmin = obj.common.meshServerRightsArrayToNumber(domain.authstrategies[req.user.strategy].newaccountsrights); } // If there are specific SSO server rights, use these instead. + if (domain.authstrategies[req.user.strategy].newaccountsrights) { user.siteadmin = obj.common.meshServerRightsArrayToNumber(domain.authstrategies[req.user.strategy].newaccountsrights); } // If there are specific SSO server rights, use these instead. if (newAccountRealms) { user.groups = newAccountRealms; } // New accounts automatically part of some groups (Realms). obj.users[userid] = user; // Auto-join any user groups var newaccountsusergroups = null; if (typeof domain.newaccountsusergroups == 'object') { newaccountsusergroups = domain.newaccountsusergroups; } - if (typeof domain.authstrategies[authStrategy].newaccountsusergroups == 'object') { newaccountsusergroups = domain.authstrategies[req.user.strategy].newaccountsusergroups; } + if (typeof domain.authstrategies[req.user.strategy].newaccountsusergroups == 'object') { newaccountsusergroups = domain.authstrategies[req.user.strategy].newaccountsusergroups; } if (newaccountsusergroups) { for (var i in newaccountsusergroups) { var ugrpid = newaccountsusergroups[i]; @@ -2684,13 +2742,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } } - if (typeof domain.authstrategies[authStrategy].groups == 'object') { + if (groups.enabled === true) { // Sync the user groups if enabled - if ((typeof domain.authstrategies[authStrategy].groups.sync == 'object') && (domain.authstrategies[authStrategy].groups.sync.enabled === true)) { syncExternalUserGroups(domain, user, userMemberships, authStrategy) } - + if (groups.syncEnabled === true) { + // Set groupType to the preset name if it exists, otherwise use the strategy name + const groupType = domain.authstrategies[req.user.strategy].custom?.preset ? domain.authstrategies[req.user.strategy].custom.preset : req.user.strategy; + syncExternalUserGroups(domain, user, groups.syncMemberships, groupType); + } // See if the user is a member of the site admin group. - if (typeof siteAdminGroup === 'string') { - parent.debug('authlog', `${authStrategy.toUpperCase()}: Granting site admin privilages to new user "${user.name}" found in admin group: ${siteAdminGroup}`); + if (groups.grantAdmin === true) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" Granting site admin privilages`); user.siteadmin = 0xFFFFFFFF; } } @@ -2715,7 +2776,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF obj.parent.DispatchEvent(targets, obj, loginEvent); } else { // New users not allowed - parent.debug('authlog', `${authStrategy.toUpperCase()}: Can\'t create new user, account creation is not allowed`); + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: LOGIN FAILED: USER: "${req.user.sid}" New accounts are not allowed`); req.session.loginmode = 1; req.session.messageid = 100; // Unable to create account. res.redirect(domain.url + getQueryPortion(req)); @@ -2726,19 +2787,19 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var userChanged = false; if ((req.user.name != null) && (req.user.name != user.name)) { user.name = req.user.name; userChanged = true; } if ((req.user.email != null) && (req.user.email != user.email)) { user.email = req.user.email; user.emailVerified = true; userChanged = true; } - - if (typeof domain.authstrategies[authStrategy].groups == 'object') { - // Sync the user groups if enabled - if ((typeof domain.authstrategies[authStrategy].groups.sync == 'object') && (domain.authstrategies[authStrategy].groups.sync.enabled === true)) { syncExternalUserGroups(domain, user, userMemberships, authStrategy) } + if (groups.enabled === true) { + // Sync the user groups if enabled + if (groups.syncEnabled === true) { + syncExternalUserGroups(domain, user, groups.syncMemberships, req.user.strategy) + } // See if the user is a member of the site admin group. - if ((typeof domain.authstrategies[authStrategy].groups.siteadmin !== 'undefined') && (domain.authstrategies[authStrategy].groups.siteadmin !== null)) { - if ((typeof siteAdminGroup === 'string') && (user.siteadmin !== 0xFFFFFFFF)) { - parent.debug('authlog', `${authStrategy.toUpperCase()}: Granting site admin privilages to user "${user.name}" found in administrator group: ${siteAdminGroup}`); - user.siteadmin = 0xFFFFFFFF; - userChanged = true; - } else if ((siteAdminGroup === false) && (user.siteadmin === 0xFFFFFFFF)) { - parent.debug('authlog', `${authStrategy.toUpperCase()}: Revoking site admin privilages from user "${user.name}" since they are not found in any administrator groups.`); + if (groups.siteAdminEnabled === true) { + if (groups.grantAdmin === true) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" Granting site admin privilages`); + if (user.siteadmin !== 0xFFFFFFFF) { user.siteadmin = 0xFFFFFFFF; userChanged = true; } + } else if ((groups.revokeAdmin === true) && (user.siteadmin === 0xFFFFFFFF)) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: GROUPS: USER: "${req.user.sid}" Revoking site admin privilages.`); delete user.siteadmin; userChanged = true; } @@ -2747,6 +2808,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Update db record for user if there are changes detected if (userChanged) { + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: CHANGED: USER: "${req.user.sid}" Updating user database entry`); obj.db.SetUser(user); // Event user change @@ -2764,12 +2826,50 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF const ua = obj.getUserAgentInfo(req); const loginEvent = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'login', msgid: 107, msgArgs: [req.clientIp, ua.browserStr, ua.osStr], msg: 'Account login', domain: domain.id, ip: req.clientIp, userAgent: req.headers['user-agent'], twoFactorType: 'sso' }; obj.parent.DispatchEvent(targets, obj, loginEvent); - parent.debug('authlog', `${authStrategy.toUpperCase()}: User Logged In: Name: ${user.name} ID: ${user._id}`); + parent.authLog('handleStrategyLogin', `${req.user.strategy.toUpperCase()}: LOGIN SUCCESS: USER: "${req.user.sid}"`); } - } else { parent.debug('warn', 'handleStrategyLogin: FAILED - No user'); } + } else if (req.session && req.session.userid && obj.users[req.session.userid]) { + parent.authLog('handleStrategyLogin', `User Already Authorised "${(req.session.passport && req.session.passport.user) ? req.session.passport.user : req.session.userid }"`); + } else { + parent.authLog('handleStrategyLogin', `LOGIN FAILED: REQUEST CONTAINS NO USER OR SID`); + } //res.redirect(domain.url); // This does not handle cookie correctly. res.set('Content-Type', 'text/html'); - res.end(''); + let url = domain.url; + if (Object.keys(req.query).length > 0) { url += "?" + Object.keys(req.query).map(function(key) { return encodeURIComponent(key) + "=" + encodeURIComponent(req.query[key]); }).join("&"); } + + // check for relaystate is set, test against configured server name and accepted query params + if(req.body && req.body.RelayState !== undefined){ + var relayState = decodeURIComponent(req.body.RelayState); + var serverName = (obj.getWebServerName(domain, req)).replaceAll('.','\\.'); + + var regexstr = `(?<=https:\\/\\/(?:.+?\\.)?${serverName}\\/?)` + + `.*((?<=([\\?&])gotodevicename=(.{64})|` + + `gotonode=(.{64})|` + + `gotodeviceip=(((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4})|` + + `gotodeviceip=(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::([0-9a-fA-F]{1,4}:){1,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:)` + + `lang=(.{5})|` + + `sitestyle=(\\d+)|` + + `user=(.{64})|` + + `pass=(.{256})|` + + `key=|` + + `locale=|` + + `gotomesh=(.{64})|` + + `gotouser=(.{0,64})|` + + `gotougrp=(.{64})|` + + `debug=|` + + `filter=|` + + `webrtc=|` + + `hide=|` + + `viewmode=(\\d+)(?=[\\&]|\\b)))`; + + var regex = new RegExp(regexstr); + if(regex.test(relayState)){ + url = relayState; + } + } + + res.end(''); } // Indicates that any request to "/" should render "default" or "login" depending on login state @@ -2788,7 +2888,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Check if we are in maintenance mode if ((parent.config.settings.maintenancemode != null) && (req.query.loginscreen !== '1')) { parent.debug('web', 'handleLoginRequest: Server under maintenance.'); - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 3, msgid: 13, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 3, msgid: 13, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } @@ -2813,7 +2913,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } else if (req.query.user && req.query.pass) { // User credentials are being passed in the URL. WARNING: Putting credentials in a URL is bad security... but people are requesting this option. obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid, passhint, loginOptions) { - if ((userid != null) && (err == null)) { + // 2FA is not supported in URL authentication method. If user has 2FA enabled, this login method fails. + var user = obj.users[userid]; + if ((err == null) && checkUserOneTimePasswordRequired(domain, user, req, loginOptions) == true) { + handleRootRequestEx(req, res, domain, direct); + } else if ((userid != null) && (err == null)) { // Login success parent.debug('web', 'handleRootRequest: user/pass in URL auth ok.'); req.session.userid = userid; @@ -2975,7 +3079,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // If the request has a "meshmessengerid", redirect to MeshMessenger // This situation happens when you get a push notification for a chat session, but are not logged in. if (req.query.meshmessengerid != null) { - res.redirect(domain.url + 'messenger?id=' + req.query.meshmessengerid + ((req.query.key != null) ? ('&key=' + req.query.key) : '')); + res.redirect(domain.url + 'messenger?id=' + encodeURIComponent(req.query.meshmessengerid) + ((req.query.key != null) ? ('&key=' + encodeURIComponent(req.query.key)) : '')); return; } @@ -3044,12 +3148,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Fetch the web state parent.debug('web', 'handleRootRequestEx: success.'); - var webstate = ''; + var webstate = '{}'; if ((err == null) && (states != null) && (Array.isArray(states)) && (states.length == 1) && (states[0].state != null)) { webstate = obj.filterUserWebState(states[0].state); } - if ((webstate == '') && (typeof domain.defaultuserwebstate == 'object')) { webstate = JSON.stringify(domain.defaultuserwebstate); } // User has no web state, use defaults. + if ((webstate == '{}') && (typeof domain.defaultuserwebstate == 'object')) { webstate = JSON.stringify(domain.defaultuserwebstate); } // User has no web state, use defaults. if (typeof domain.forceduserwebstate == 'object') { // Forces initial user web state if present, use it. var webstate2 = {}; - try { if (webstate != '') { webstate2 = JSON.parse(webstate); } } catch (ex) { } + try { if (webstate != '{}') { webstate2 = JSON.parse(webstate); } } catch (ex) { } for (var i in domain.forceduserwebstate) { webstate2[i] = domain.forceduserwebstate[i]; } webstate = JSON.stringify(webstate2); } @@ -3059,7 +3163,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); } // Server features - var serverFeatures = 127; + var serverFeatures = 255; if (domain.myserver === false) { serverFeatures = 0; } // 64 = Show "My Server" tab else if (typeof domain.myserver == 'object') { if (domain.myserver.backup !== true) { serverFeatures -= 1; } // Disallow simple server backups @@ -3068,14 +3172,26 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (domain.myserver.errorlog !== true) { serverFeatures -= 8; } // Disallow show server crash log if (domain.myserver.console !== true) { serverFeatures -= 16; } // Disallow server console if (domain.myserver.trace !== true) { serverFeatures -= 32; } // Disallow server tracing + if (domain.myserver.config !== true) { serverFeatures -= 128; } // Disallow server configuration } if (obj.db.databaseType != 1) { // If not using NeDB, we can't backup using the simple system. if ((serverFeatures & 1) != 0) { serverFeatures -= 1; } // Disallow server backups if ((serverFeatures & 2) != 0) { serverFeatures -= 2; } // Disallow simple server restore } + // Get WebRTC configuration + var webRtcConfig = null; + if (obj.parent.config.settings && obj.parent.config.settings.webrtcconfig && (typeof obj.parent.config.settings.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtcconfig)).replace(/'/g, '%27'); } + else if (args.webrtcconfig && (typeof args.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(args.webrtcconfig)).replace(/'/g, '%27'); } + + // Load default page style or new modern ui + var uiViewMode = 'default'; + var webstateJSON = JSON.parse(webstate); + if (webstateJSON && webstateJSON.uiViewMode == 3) { uiViewMode = 'default3'; } + if (domain.sitestyle == 3) { uiViewMode = 'default3'; } + if (req.query.sitestyle == 3) { uiViewMode = 'default3'; } // Refresh the session - render(dbGetFunc.req, dbGetFunc.res, getRenderPage('default', dbGetFunc.req, domain), getRenderArgs({ + render(dbGetFunc.req, dbGetFunc.res, getRenderPage(uiViewMode, dbGetFunc.req, domain), getRenderArgs({ authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, @@ -3099,7 +3215,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF amtscanoptions: amtscanoptions, pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports(), webRelayPort: ((args.relaydns != null) ? ((typeof args.aliasport == 'number') ? args.aliasport : args.port) : ((parent.webrelayserver != null) ? ((typeof args.relayaliasport == 'number') ? args.relayaliasport : parent.webrelayserver.port) : 0)), - webRelayDns: ((args.relaydns != null) ? args.relaydns[0] : '') + webRelayDns: ((args.relaydns != null) ? args.relaydns[0] : ''), + hidePowerTimeline: (domain.hidepowertimeline ? 'true' : 'false'), + showNotesPanel: (domain.shownotespanel ? 'true' : 'false'), + userSessionsSort: (domain.usersessionssort ? domain.usersessionssort : 'SessionId'), + webrtcconfig: webRtcConfig }, dbGetFunc.req, domain), user); } xdbGetFunc.req = req; @@ -3218,6 +3338,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((typeof domain.terminal == 'object') && (domain.terminal.sshconnect === false)) { features2 += 0x01000000; } // Remove the "SSH Connect" button in the "Terminal" tab when the device is agent managed if ((parent.msgserver != null) && (parent.msgserver.providers != 0)) { features2 += 0x02000000; } // User messaging server is enabled if ((parent.msgserver != null) && (parent.msgserver.providers != 0) && ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.msg2factor != false))) { features2 += 0x04000000; } // User messaging 2FA is allowed + if (domain.scrolltotop == true) { features2 += 0x08000000; } // Show the "Scroll to top" button + if (domain.devicesearchbargroupname === true) { features2 += 0x10000000; } // Search bar will find by group name too + if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.duo2factor != false)) && (typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) { features2 += 0x20000000; } // using Duo for 2FA is allowed + if (domain.showmodernuitoggle == true) { features2 += 0x40000000; } // Indicates that the new UI should be shown return { features: features, features2: features2 }; } @@ -3256,6 +3380,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Check if we can use OTP tokens with email. We can't use email for 2FA password recovery (loginmode 5). var otpemail = (loginmode != 5) && (domain.mailserver != null) && (req.session != null) && ((req.session.temail === 1) || (typeof req.session.temail == 'string')); if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; } + var otpduo = (req.session != null) && (req.session.tduo === 1); + if (((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.duo2factor == false)) || (typeof domain.duo2factor != 'object')) { otpduo = false; } var otpsms = (parent.smsserver != null) && (req.session != null) && (req.session.tsms === 1); if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.sms2factor == false)) { otpsms = false; } var otpmsg = (parent.msgserver != null) && (req.session != null) && (req.session.tmsg === 1); @@ -3274,9 +3400,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (typeof domain.authstrategies.twitter == 'object') { authStrategies.push('twitter'); } if (typeof domain.authstrategies.google == 'object') { authStrategies.push('google'); } if (typeof domain.authstrategies.github == 'object') { authStrategies.push('github'); } - if (typeof domain.authstrategies.reddit == 'object') { authStrategies.push('reddit'); } if (typeof domain.authstrategies.azure == 'object') { authStrategies.push('azure'); } - if (typeof domain.authstrategies.oidc == 'object') { authStrategies.push('oidc'); } + if (typeof domain.authstrategies.oidc == 'object') { + if (obj.common.validateObject(domain.authstrategies.oidc.custom) && obj.common.validateString(domain.authstrategies.oidc.custom.preset)) { + authStrategies.push('oidc-' + domain.authstrategies.oidc.custom.preset); + } else { + authStrategies.push('oidc'); + } + } if (typeof domain.authstrategies.intel == 'object') { authStrategies.push('intel'); } if (typeof domain.authstrategies.jumpcloud == 'object') { authStrategies.push('jumpcloud'); } if (typeof domain.authstrategies.saml == 'object') { authStrategies.push('saml'); } @@ -3299,9 +3430,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF newAccountCaptchaImage = 'newAccountCaptcha.ashx?x=' + newAccountCaptcha; } + // Check for flash errors from passport.js and make the array unique + var flashErrors = []; + if (req.session.flash && req.session.flash.error) { + flashErrors = obj.common.uniqueArray(req.session.flash.error); + req.session.flash = null; + } + // Render the login page render(req, res, - getRenderPage((domain.sitestyle == 2) ? 'login2' : 'login', req, domain), + getRenderPage((domain.sitestyle >= 2) ? 'login2' : 'login', req, domain), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(domain), @@ -3320,11 +3458,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF footer: (domain.loginfooter == null) ? '' : domain.loginfooter, hkey: encodeURIComponent(hardwareKeyChallenge).replace(/'/g, '%27'), messageid: msgid, + flashErrors: JSON.stringify(flashErrors), passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, welcomePictureFullScreen: ((typeof domain.welcomepicturefullscreen == 'boolean') ? domain.welcomepicturefullscreen : false), hwstate: hwstate, otpemail: otpemail, + otpduo: otpduo, otpsms: otpsms, otpmsg: otpmsg, otppush: otppush, @@ -3332,8 +3472,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF twoFactorCookieDays: twoFactorCookieDays, authStrategies: authStrategies.join(','), loginpicture: (typeof domain.loginpicture == 'string'), - tokenTimeout: twoFactorTimeout // Two-factor authentication screen timeout in milliseconds - }, req, domain, (domain.sitestyle == 2) ? 'login2' : 'login')); + tokenTimeout: twoFactorTimeout, // Two-factor authentication screen timeout in milliseconds, + renderLanguages: obj.renderLanguages, + showLanguageSelect: domain.showlanguageselect ? domain.showlanguageselect : false, + }, req, domain, (domain.sitestyle >= 2) ? 'login2' : 'login')); } // Handle a post request on the root @@ -3393,7 +3535,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (typeof obj.args.trustedcert == 'boolean') return obj.args.trustedcert; // If the status of the cert specified, use that. if (obj.args.tlsoffload != null) return true; // We are using TLS offload, a real cert is likely used. if (obj.parent.config.letsencrypt != null) return (obj.parent.config.letsencrypt.production === true); // We are using Let's Encrypt, real cert in use if production is set to true. - if (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) return false; // Our cert is issued by self-signed cert. + if ((typeof obj.certificates.WebIssuer == 'string') && (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0)) return false; // Our cert is issued by self-signed cert. if (obj.certificates.CommonName.indexOf('.') == -1) return false; // Our cert is named with a fake name return true; // This is a guess } @@ -3428,7 +3570,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if ((node == null) || ((rights & 8) == 0) || ((rights != 0xFFFFFFFF) && ((rights & 512) != 0))) { res.redirect(domain.url + getQueryPortion(req)); return; } var logoutcontrols = { name: user.name }; - var extras = (req.query.key != null) ? ('&key=' + req.query.key) : ''; + var extras = (req.query.key != null) ? ('&key=' + encodeURIComponent(req.query.key)) : ''; if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button // Create a authentication cookie @@ -3485,7 +3627,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (req.session.userid.split('/')[1] != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain var user = obj.users[req.session.userid]; var logoutcontrols = { name: user.name }; - var extras = (req.query.key != null) ? ('&key=' + req.query.key) : ''; + var extras = (req.query.key != null) ? ('&key=' + encodeURIComponent(req.query.key)) : ''; if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()).split('\'').join('\\\''), logoutControls: encodeURIComponent(JSON.stringify(logoutcontrols)).replace(/'/g, '%27') }, req, domain)); } else { @@ -3504,7 +3646,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (req.session.userid.split('/')[1] != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain var user = obj.users[req.session.userid]; var logoutcontrols = { name: user.name }; - var extras = (req.query.key != null) ? ('&key=' + req.query.key) : ''; + var extras = (req.query.key != null) ? ('&key=' + encodeURIComponent(req.query.key)) : ''; if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ terms: encodeURIComponent(data).split('\'').join('\\\''), logoutControls: encodeURIComponent(JSON.stringify(logoutcontrols)).replace(/'/g, '%27') }, req, domain)); } else { @@ -3519,7 +3661,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (req.session.userid.split('/')[1] != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain var user = obj.users[req.session.userid]; var logoutcontrols = { name: user.name }; - var extras = (req.query.key != null) ? ('&key=' + req.query.key) : ''; + var extras = (req.query.key != null) ? ('&key=' + encodeURIComponent(req.query.key)) : ''; if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ logoutControls: encodeURIComponent(JSON.stringify(logoutcontrols)).replace(/'/g, '%27') }, req, domain)); } else { @@ -3537,7 +3679,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Check if we are in maintenance mode if (parent.config.settings.maintenancemode != null) { - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 3, msgid: 13, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 3, msgid: 13, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } @@ -3551,7 +3693,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var user2 = idSplit[4] + '/' + idSplit[5] + '/' + idSplit[6] if (!req.session || !req.session.userid) { // Redirect to login page - if (req.query.key != null) { res.redirect(domain.url + '?key=' + req.query.key + '&meshmessengerid=' + req.query.id); } else { res.redirect(domain.url + '?meshmessengerid=' + req.query.id); } + if (req.query.key != null) { res.redirect(domain.url + '?key=' + encodeURIComponent(req.query.key) + '&meshmessengerid=' + encodeURIComponent(req.query.id)); } else { res.redirect(domain.url + '?meshmessengerid=' + encodeURIComponent(req.query.id)); } return; } if ((req.session.userid != user1) && (req.session.userid != user2)) { res.sendStatus(404); return; } @@ -3559,11 +3701,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Get WebRTC configuration var webRtcConfig = null; - if (obj.parent.config.settings && obj.parent.config.settings.webrtconfig && (typeof obj.parent.config.settings.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtconfig)).replace(/'/g, '%27'); } - else if (args.webrtconfig && (typeof args.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(args.webrtconfig)).replace(/'/g, '%27'); } + if (obj.parent.config.settings && obj.parent.config.settings.webrtcconfig && (typeof obj.parent.config.settings.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtcconfig)).replace(/'/g, '%27'); } + else if (args.webrtcconfig && (typeof args.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(args.webrtcconfig)).replace(/'/g, '%27'); } // Setup other options - var options = { webrtconfig: webRtcConfig }; + var options = { webrtcconfig: webRtcConfig }; if (typeof domain.meshmessengertitle == 'string') { options.meshMessengerTitle = domain.meshmessengertitle; } else { options.meshMessengerTitle = '!'; } // Get the userid and name @@ -3645,6 +3787,31 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF res.send(Buffer.from(getRootCertBase64(), 'base64')); } + // Return a customised mainifest.json for PWA + function handleManifestRequest(req, res){ + const domain = getDomain(req); + if (domain == null) { parent.debug('web', 'handleManifestRequest: no domain'); res.sendStatus(404); return; } + if ((obj.userAllowedIp != null) && (checkIpAddressEx(req, res, obj.userAllowedIp, false) === false)) { parent.debug('web', 'handleManifestRequest: invalid ip'); return; } // Check server-wide IP filter only. + parent.debug('web', 'handleManifestRequest()'); + var manifest = { + "name": (domain.title != null) ? domain.title : 'MeshCentral', + "short_name": (domain.title != null) ? domain.title : 'MeshCentral', + "description": "Open source web based, remote computer management.", + "scope": ".", + "start_url": "/", + "display": "fullscreen", + "orientation": "any", + "theme_color": "#ffffff", + "background_color": "#ffffff", + "icons": [{ + "src": "pwalogo.png", + "sizes": "512x512", + "type": "image/png" + }] + }; + res.json(manifest); + } + // Handle user public file downloads function handleDownloadUserFiles(req, res) { const domain = checkUserIpAddress(req, res); @@ -3653,6 +3820,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (obj.common.validateString(req.path, 1, 4096) == false) { res.sendStatus(404); return; } var domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = ''; + if (spliturl[1] != 'userfiles') { spliturl.splice(1,1); } // remove domain.id from url for domains without dns if ((spliturl.length < 3) || (obj.common.IsFilenameValid(spliturl[2]) == false) || (domain.userQuota == -1)) { res.sendStatus(404); return; } if (domain.id != '') { domainname = 'domain-' + domain.id; } var path = obj.path.join(obj.filespath, domainname + '/user-' + spliturl[2] + '/Public'); @@ -3665,10 +3833,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF setContentDispositionHeader(res, 'application/octet-stream', filename, null, 'file.bin'); try { res.sendFile(obj.path.resolve(__dirname, path)); } catch (e) { res.sendStatus(404); } } else { - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'download2' : 'download', req, domain), getRenderArgs({ rootCertLink: getRootCertLink(domain), messageid: 1, fileurl: req.path + '?download=1', filename: filename, filesize: stat.size }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'download2' : 'download', req, domain), getRenderArgs({ rootCertLink: getRootCertLink(domain), messageid: 1, fileurl: req.path + '?download=1', filename: filename, filesize: stat.size }, req, domain)); } } else { - render(req, res, getRenderPage((domain.sitestyle == 2) ? 'download2' : 'download', req, domain), getRenderArgs({ rootCertLink: getRootCertLink(domain), messageid: 2 }, req, domain)); + render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'download2' : 'download', req, domain), getRenderArgs({ rootCertLink: getRootCertLink(domain), messageid: 2 }, req, domain)); } } @@ -3704,7 +3872,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Handle download of a server file by an agent function handleAgentDownloadFile(req, res) { - const domain = checkUserIpAddress(req, res); + const domain = checkAgentIpAddress(req, res); if (domain == null) { return; } if (req.query.c == null) { res.sendStatus(404); return; } @@ -3767,6 +3935,36 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } } + // Handle PWA logo request + function handlePWALogoRequest(req, res) { + const domain = checkUserIpAddress(req, res); + if (domain == null) { return; } + + //res.set({ 'Cache-Control': 'max-age=86400' }); // 1 day + if (domain.pwalogo) { + if ((parent.configurationFiles != null) && (parent.configurationFiles[domain.pwalogo] != null)) { + // Use the logo in the database + res.set({ 'Content-Type': domain.pwalogo.toLowerCase().endsWith('.png') ? 'image/png' : 'image/jpeg' }); + res.send(parent.configurationFiles[domain.pwalogo]); + return; + } else { + // Use the logo on file + try { res.sendFile(obj.common.joinPath(obj.parent.datapath, domain.pwalogo)); return; } catch (ex) { } + } + } + + if ((domain.webpublicpath != null) && (obj.fs.existsSync(obj.path.join(domain.webpublicpath, 'android-chrome-512x512.png')))) { + // Use the domain logo picture + try { res.sendFile(obj.path.join(domain.webpublicpath, 'android-chrome-512x512.png')); } catch (ex) { res.sendStatus(404); } + } else if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'android-chrome-512x512.png'))) { + // Use the override logo picture + try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, 'android-chrome-512x512.png')); } catch (ex) { res.sendStatus(404); } + } else { + // Use the default logo picture + try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'android-chrome-512x512.png')); } catch (ex) { res.sendStatus(404); } + } + } + // Handle translation request function handleTranslationsRequest(req, res) { const domain = checkUserIpAddress(req, res); @@ -3850,7 +4048,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } var imagefile = 'images/mainwelcome.jpg'; - if (domain.sitestyle == 2) { imagefile = 'images/login/back.png'; } + if (domain.sitestyle >= 2) { imagefile = 'images/login/back.png'; } if (domain.webpublicpath != null) { obj.fs.exists(obj.path.join(domain.webpublicpath, imagefile), function (exists) { if (exists) { @@ -3997,7 +4195,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (typeof c.pid != 'string') { res.sendStatus(404); return; } // Check the expired time, expire message. - if ((c.e != null) && (c.e <= Date.now())) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } + if ((c.e != null) && (c.e <= Date.now())) { render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } obj.db.Get('deviceshare-' + c.pid, function (err, docs) { if ((err != null) || (docs == null) || (docs.length != 1)) { res.sendStatus(404); return; } @@ -4043,17 +4241,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Serve the guest sharing page function handleSharingRequestEx(req, res, domain, c) { // Check the expired time, expire message. - if ((c.expire != null) && (c.expire <= Date.now())) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } + if ((c.expire != null) && (c.expire <= Date.now())) { render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } // Check the public id obj.db.GetAllTypeNodeFiltered([c.nid], domain.id, 'deviceshare', null, function (err, docs) { // Check if any sharing links are present, expire message. - if ((err != null) || (docs.length == 0)) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } + if ((err != null) || (docs.length == 0)) { render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } // Search for the device share public identifier, expire message. var found = false; for (var i = 0; i < docs.length; i++) { if ((docs[i].publicid == c.pid) && ((docs[i].extrakey == null) || (docs[i].extrakey === c.k))) { found = true; } } - if (found == false) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } + if (found == false) { render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 12, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } // Get information about this node obj.db.Get(c.nid, function (err, nodes) { @@ -4061,7 +4259,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var node = nodes[0]; // Check the start time, not yet valid message. - if ((c.start != null) && (c.expire != null) && ((c.start > Date.now()) || (c.start > c.expire))) { render(req, res, getRenderPage((domain.sitestyle == 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 11, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } + if ((c.start != null) && (c.expire != null) && ((c.start > Date.now()) || (c.start > c.expire))) { render(req, res, getRenderPage((domain.sitestyle >= 2) ? 'message2' : 'message', req, domain), getRenderArgs({ titleid: 2, msgid: 11, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); return; } // If this is a web relay share, check if this feature is active if ((c.p == 8) || (c.p == 16)) { @@ -4485,6 +4683,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Subscribe to all events we are allowed to receive obj.subscribe = function (userid, target) { const user = obj.users[userid]; + if (user == null) return; const subscriptions = [userid, 'server-allusers']; if (user.siteadmin != null) { // Allow full site administrators of users with all events rights to see all events. @@ -4826,11 +5025,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF ws._socket.resume(); } else { // If TLS is going to be used, setup a TLS socket - var tlsoptions = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; + var tlsoptions = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false }; if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; } ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () { // The TLS connection method is the same as TCP, but located a bit differently. - parent.debug('webrelay', 'TLS connected to ' + node.host + ':' + port + '.'); + parent.debug('webrelay', user.name + ' - TLS connected to ' + node.host + ':' + port + '.'); ws.forwardclient.xstate = 1; ws._socket.resume(); }); @@ -4843,7 +5042,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF ws.forwardclient.on('data', function (data) { if (typeof data == 'string') { data = Buffer.from(data, 'binary'); } if (obj.parent.debugLevel >= 1) { // DEBUG - parent.debug('webrelaydata', 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); + parent.debug('webrelaydata', user.name + ' - TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); //if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); } } if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor @@ -4858,13 +5057,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // If the TCP connection closes, disconnect the associated web socket. ws.forwardclient.on('close', function () { - parent.debug('webrelay', 'TCP relay disconnected from ' + node.host + ':' + port + '.'); + parent.debug('webrelay', user.name + ' - TCP relay disconnected from ' + node.host + ':' + port + '.'); try { ws.close(); } catch (e) { } }); // If the TCP connection causes an error, disconnect the associated web socket. ws.forwardclient.on('error', function (err) { - parent.debug('webrelay', 'TCP relay error from ' + node.host + ':' + port + ': ' + err); + parent.debug('webrelay', user.name + ' - TCP relay error from ' + node.host + ':' + port + ': ' + err); try { ws.close(); } catch (e) { } }); @@ -4875,7 +5074,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (node.intelamt.tls == 0) { // A TCP connection to Intel AMT just connected, start forwarding. ws.forwardclient.connect(port, node.host, function () { - parent.debug('webrelay', 'TCP relay connected to ' + node.host + ':' + port + '.'); + parent.debug('webrelay', user.name + ' - TCP relay connected to ' + node.host + ':' + port + '.'); ws.forwardclient.xstate = 1; ws._socket.resume(); }); @@ -5294,6 +5493,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Get the agent filename var meshagentFilename = argentInfo.rname; if ((domain.agentcustomization != null) && (typeof domain.agentcustomization.filename == 'string')) { meshagentFilename = domain.agentcustomization.filename; } + if (argentInfo.rname.endsWith('.apk') && !meshagentFilename.endsWith('.apk')) { meshagentFilename = meshagentFilename + '.apk'; } if (argentInfo.mtime != null) { res.setHeader('Last-Modified', argentInfo.mtime.toUTCString()); } if (req.query.zip == 1) { if (argentInfo.zdata != null) { setContentDispositionHeader(res, 'application/octet-stream', meshagentFilename + '.zip', null, 'meshagent.zip'); res.send(argentInfo.zdata); } else { try { res.sendStatus(404); } catch (ex) { } } return; } // Send compressed agent setContentDispositionHeader(res, 'application/octet-stream', meshagentFilename, null, 'meshagent'); @@ -5337,13 +5537,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly. var xdomain = (domain.dns == null) ? domain.id : ''; if (xdomain != '') xdomain += '/'; - var meshsettings = '\r\nMeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n'; - if (obj.args.lanonly != true) { meshsettings += 'MeshServer=wss://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { - meshsettings += 'MeshServer=local\r\n'; - if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; } + var meshsettings = ''; + if (req.query.ac != '4') { // If MeshCentral Assistant Monitor Mode, DONT INCLUDE SERVER DETAILS! + meshsettings += '\r\nMeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n'; + if (obj.args.lanonly != true) { meshsettings += 'MeshServer=wss://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { + meshsettings += 'MeshServer=local\r\n'; + if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; } + } + if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + encodeURIComponent(req.query.tag) + '\r\n'; } + if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } } - if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } - if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } if (req.query.id == '10006') { // Assistant settings and customizations if ((req.query.ac != null)) { meshsettings += 'AutoConnect=' + req.query.ac + '\r\n'; } // Set MeshCentral Assistant flags if needed. 0x01 = Always Connected, 0x02 = Not System Tray if (obj.args.assistantconfig) { for (var i in obj.args.assistantconfig) { meshsettings += obj.args.assistantconfig[i] + '\r\n'; } } @@ -5414,22 +5617,29 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Send meshcmd for a specific platform back var agentid = parseInt(req.query.meshcmd); - + // If the agentid is 3 or 4, check if we have a signed MeshCmd.exe - if ((agentid == 3) && (obj.parent.meshAgentBinaries[11000] != null)) { // Signed Windows MeshCmd.exe x86 + if ((agentid == 3) && (obj.parent.meshAgentBinaries[11000] != null)) { // Signed Windows MeshCmd.exe x86-32 var stats = null, meshCmdPath = obj.parent.meshAgentBinaries[11000].path; try { stats = obj.fs.statSync(meshCmdPath); } catch (e) { } if ((stats != null)) { setContentDispositionHeader(res, 'application/octet-stream', 'meshcmd.exe', null, 'meshcmd'); res.sendFile(meshCmdPath); return; } - } else if ((agentid == 4) && (obj.parent.meshAgentBinaries[11001] != null)) { // Signed Windows MeshCmd64.exe x64 + } else if ((agentid == 4) && (obj.parent.meshAgentBinaries[11001] != null)) { // Signed Windows MeshCmd64.exe x86-64 var stats = null, meshCmd64Path = obj.parent.meshAgentBinaries[11001].path; try { stats = obj.fs.statSync(meshCmd64Path); } catch (e) { } if ((stats != null)) { setContentDispositionHeader(res, 'application/octet-stream', 'meshcmd.exe', null, 'meshcmd'); res.sendFile(meshCmd64Path); return; } + } else if ((agentid == 43) && (obj.parent.meshAgentBinaries[11002] != null)) { // Signed Windows MeshCmd64.exe ARM-64 + var stats = null, meshCmdAMR64Path = obj.parent.meshAgentBinaries[11002].path; + try { stats = obj.fs.statSync(meshCmdAMR64Path); } catch (e) { } + if ((stats != null)) { + setContentDispositionHeader(res, 'application/octet-stream', 'meshcmd-arm64.exe', null, 'meshcmd'); + res.sendFile(meshCmdAMR64Path); return; + } } // No signed agents, we are going to merge a new MeshCmd. @@ -5445,7 +5655,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF res.sendFile(argentInfo.signedMeshCmdPath); } else { // Merge JavaScript to a unsigned agent and send that. - console.log('aa', argentInfo.path); obj.parent.exeHandler.streamExeWithJavaScript({ platform: argentInfo.platform, sourceFileName: argentInfo.path, destinationStream: res, js: Buffer.from(obj.parent.defaultMeshCmd, 'utf8'), peinfo: argentInfo.pe }); } return; @@ -5519,7 +5728,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (user != null) { meshaction.username = user.name; } if (req.query.key != null) { meshaction.loginKey = req.query.key; } var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified - if (obj.args.lanonly != true) { meshaction.serverUrl = 'wss://' + obj.getWebServerName(domain, req) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; } + if (obj.args.lanonly != true) { meshaction.serverUrl = 'wss://' + obj.getWebServerName(domain, req) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : (domain.id + '/')) + 'meshrelay.ashx'; } setContentDispositionHeader(res, 'application/octet-stream', 'meshaction.txt', null, 'meshaction.txt'); res.send(JSON.stringify(meshaction, null, ' ')); @@ -5624,9 +5833,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF agentinfo: agentinfo, filestats: filestats, currentAgent: agentinfo.hashhex.startsWith(fileSplit[1].toLowerCase()), - downloadUrl: req.originalUrl.split('?')[0] + '?dldump=' + file + (req.query.key ? ('&key=' + req.query.key) : ''), - deleteUrl: req.originalUrl.split('?')[0] + '?deldump=' + file + (req.query.key ? ('&key=' + req.query.key) : ''), - agentUrl: req.originalUrl.split('?')[0] + '?id=' + agentinfo.id + (req.query.key ? ('&key=' + req.query.key) : ''), + downloadUrl: req.originalUrl.split('?')[0] + '?dldump=' + file + (req.query.key ? ('&key=' + encodeURIComponent(req.query.key)) : ''), + deleteUrl: req.originalUrl.split('?')[0] + '?deldump=' + file + (req.query.key ? ('&key=' + encodeURIComponent(req.query.key)) : ''), + agentUrl: req.originalUrl.split('?')[0] + '?id=' + agentinfo.id + (req.query.key ? ('&key=' + encodeURIComponent(req.query.key)) : ''), time: new Date(filestats.ctime) }); } @@ -5642,7 +5851,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF response += '' + d.fileSplit[1].toLowerCase() + '' + d.fileSplit[2] + 'Delete'; } } - response += 'Mesh Agents'; + response += 'Mesh Agents'; res.send(response); return; } @@ -5653,9 +5862,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var response = 'Mesh Agents Cores'; response += ''; for (var i in parent.defaultMeshCores) { - response += ''; + response += ''; } - response += '
        NameSizeCompDecompressed Hash SHA384
        ' + i.split(' ').join(' ') + '' + parent.defaultMeshCores[i].length + (req.query.key ? ('?key=' + req.query.key) : '') + '' + parent.defaultMeshCoresDeflate[i].length + '' + Buffer.from(parent.defaultMeshCoresHash[i], 'binary').toString('hex') + '
        ' + i.split(' ').join(' ') + '' + parent.defaultMeshCores[i].length + (req.query.key ? ('?key=' + encodeURIComponent(req.query.key)) : '') + '' + parent.defaultMeshCoresDeflate[i].length + '' + Buffer.from(parent.defaultMeshCoresHash[i], 'binary').toString('hex') + '
        Mesh Agents'; + response += 'Mesh Agents'; res.send(response); return; } @@ -5664,7 +5873,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Download mesh core var bin = parent.defaultMeshCores[req.query.dlcore]; if ((bin == null) || (bin.length < 5)) { try { res.sendStatus(404); } catch (ex) { } return; } - setContentDispositionHeader(res, 'application/octet-stream', req.query.dlcore + '.js', null, 'meshcore.js'); + setContentDispositionHeader(res, 'application/octet-stream', encodeURIComponent(req.query.dlcore) + '.js', null, 'meshcore.js'); res.send(bin.slice(4)); return; } @@ -5687,24 +5896,33 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var agentinfo = obj.parent.meshAgentBinaries[agentid]; if (domain.meshAgentBinaries && domain.meshAgentBinaries[agentid]) { argentInfo = domain.meshAgentBinaries[agentid]; } response += '' + agentinfo.id + '' + agentinfo.desc.split(' ').join(' ') + ''; - response += '' + agentinfo.rname + ''; + response += '' + agentinfo.rname + ''; if ((user.siteadmin == 0xFFFFFFFF) || ((Array.isArray(obj.parent.config.settings.agentcoredumpusers)) && (obj.parent.config.settings.agentcoredumpusers.indexOf(user._id) >= 0))) { - if ((agentid == 3) || (agentid == 4)) { response += ', PDB'; } + if ((agentid == 3) || (agentid == 4)) { response += ', PDB'; } } - if (agentinfo.zdata != null) { response += ', ZIP'; } + if (agentinfo.zdata != null) { response += ', ZIP'; } response += ''; response += '' + agentinfo.size + '' + agentinfo.hashhex + ''; - response += '' + agentinfo.rname.replace('agent', 'cmd') + ''; + response += '' + agentinfo.rname.replace('agent', 'cmd') + ''; } response += ''; - response += 'MeshCores '; - if (coreDumpsAllowed) { response += 'MeshAgent Crash Dumps'; } + response += 'MeshCores '; + if (coreDumpsAllowed) { response += 'MeshAgent Crash Dumps'; } response += ''; res.send(response); return; } }; + // generate the server url + obj.generateBaseURL = function (domain, req) { + var serverName = obj.getWebServerName(domain, req); + var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified + var xdomain = (domain.dns == null) ? domain.id : ''; + if (xdomain != '') xdomain += '/'; + return ('https://' + serverName + ':' + httpsPort + '/' + xdomain); + } + // Get the web server hostname. This may change if using a domain with a DNS name. obj.getWebServerName = function (domain, req) { if (domain.dns != null) return domain.dns; @@ -5712,6 +5930,18 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF return obj.certificates.CommonName; } + // Return true if this is an allowed HTTP request origin hostname. + obj.CheckWebServerOriginName = function (domain, req) { + if (domain.allowedorigin === true) return true; // Ignore origin + if (typeof req.headers.origin != 'string') return true; // No origin in the header, this is a desktop app + const originUrl = require('url').parse(req.headers.origin, true); + if (typeof originUrl.hostname != 'string') return false; // Origin hostname is not valid + if (Array.isArray(domain.allowedorigin)) return (domain.allowedorigin.indexOf(originUrl.hostname) >= 0); // Check if this is an allowed origin from an explicit list + if (obj.isTrustedCert(domain) === false) return true; // This server does not have a trusted certificate. + if (domain.dns != null) return (domain.dns == originUrl.hostname); // Match the domain DNS + return (obj.certificates.CommonName == originUrl.hostname); // Match the default server name + } + // Create a OSX mesh agent installer obj.handleMeshOsxAgentRequest = function (req, res) { const domain = getDomain(req, res); @@ -5758,7 +5988,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF meshsettings += 'MeshServer=local\r\n'; if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; } } - if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } + if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + encodeURIComponent(req.query.tag) + '\r\n'; } if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; } if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } } @@ -5779,8 +6009,36 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var archive = require('archiver')('zip', { level: 5 }); // Sets the compression method. archive.on('error', function (err) { throw err; }); + // Customize the mesh agent file name + var meshfilename = 'MeshAgent-' + mesh.name + '.zip'; + var meshexecutablename = 'meshagent'; + var meshmpkgname = 'MeshAgent.mpkg'; + if ((domain.agentcustomization != null) && (typeof domain.agentcustomization.filename == 'string')) { + meshfilename = meshfilename.split('MeshAgent').join(domain.agentcustomization.filename); + meshexecutablename = meshexecutablename.split('meshagent').join(domain.agentcustomization.filename); + meshmpkgname = meshmpkgname.split('MeshAgent').join(domain.agentcustomization.filename); + } + + // Customise the mesh agent display name + var meshdisplayname = 'Mesh Agent'; + if ((domain.agentcustomization != null) && (typeof domain.agentcustomization.displayname == 'string')) { + meshdisplayname = meshdisplayname.split('Mesh Agent').join(domain.agentcustomization.displayname); + } + + // Customise the mesh agent service name + var meshservicename = 'meshagent'; + if ((domain.agentcustomization != null) && (typeof domain.agentcustomization.servicename == 'string')) { + meshservicename = meshservicename.split('meshagent').join(domain.agentcustomization.servicename); + } + + // Customise the mesh agent company name + var meshcompanyname = 'meshagent'; + if ((domain.agentcustomization != null) && (typeof domain.agentcustomization.companyname == 'string')) { + meshcompanyname = meshcompanyname.split('meshagent').join(domain.agentcustomization.companyname); + } + // Set the agent download including the mesh name. - setContentDispositionHeader(res, 'application/octet-stream', 'MeshAgent-' + mesh.name + '.zip', null, 'MeshAgent.zip'); + setContentDispositionHeader(res, 'application/octet-stream', meshfilename, null, 'MeshAgent.zip'); archive.pipe(res); // Opens the "MeshAgentOSXPackager.zip" @@ -5799,17 +6057,34 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF readStream.on('data', function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } }); readStream.on('end', function () { var meshname = mesh.name.split(']').join('').split('[').join(''); // We can't have ']]' in the string since it will terminate the CDATA. - var welcomemsg = 'Welcome to the MeshCentral agent for MacOS\n\nThis installer will install the mesh agent for "' + meshname + '" and allow the administrator to remotely monitor and control this computer over the internet. For more information, go to https://www.meshcommander.com/meshcentral2.\n\nThis software is provided under Apache 2.0 license.\n'; + var welcomemsg = 'Welcome to the MeshCentral agent for MacOS\n\nThis installer will install the mesh agent for "' + meshname + '" and allow the administrator to remotely monitor and control this computer over the internet. For more information, go to https://meshcentral.com.\n\nThis software is provided under Apache 2.0 license.\n'; var installsize = Math.floor((argentInfo.size + meshsettings.length) / 1024); - archive.append(readStream.xxdata.toString().split('###WELCOMEMSG###').join(welcomemsg).split('###INSTALLSIZE###').join(installsize), { name: entry.fileName }); + archive.append(readStream.xxdata.toString().split('###DISPLAYNAME###').join(meshdisplayname).split('###WELCOMEMSG###').join(welcomemsg).split('###INSTALLSIZE###').join(installsize), { name: entry.fileName.replace('MeshAgent.mpkg',meshmpkgname) }); zipfile.readEntry(); }); }); + } else if (entry.fileName == 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64_LaunchAgent.plist' || + entry.fileName == 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64_LaunchDaemon.plist' || + entry.fileName == 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/Info.plist' || + entry.fileName == 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/Resources/postflight' || + entry.fileName == 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/Resources/Postflight.sh' || + entry.fileName == 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/Uninstall.command' || + entry.fileName == 'MeshAgent.mpkg/Uninstall.command') { + // This is a special file entry, we need to fix it. + zipfile.openReadStream(entry, function (err, readStream) { + readStream.on('data', function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } }); + readStream.on('end', function () { + var options = { name: entry.fileName.replace('MeshAgent.mpkg',meshmpkgname) }; + if (entry.fileName.endsWith('postflight') || entry.fileName.endsWith('Uninstall.command')) { options.mode = 493; } + archive.append(readStream.xxdata.toString().split('###SERVICENAME###').join(meshservicename).split('###COMPANYNAME###').join(meshcompanyname).split('###EXECUTABLENAME###').join(meshexecutablename), options); + zipfile.readEntry(); + }); + }); } else { // Normal file entry zipfile.openReadStream(entry, function (err, readStream) { if (err) { throw err; } - var options = { name: entry.fileName }; + var options = { name: entry.fileName.replace('MeshAgent.mpkg',meshmpkgname) }; if (entry.fileName.endsWith('postflight') || entry.fileName.endsWith('Uninstall.command')) { options.mode = 493; } archive.append(readStream, options); readStream.on('end', function () { zipfile.readEntry(); }); @@ -5818,8 +6093,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } }); zipfile.on('end', function () { - archive.file(argentInfo.path, { name: 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.bin' }); - archive.append(meshsettings, { name: 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.msh' }); + archive.file(argentInfo.path, { name: 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.bin'.replace('MeshAgent.mpkg',meshmpkgname) }); + archive.append(meshsettings, { name: 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.msh'.replace('MeshAgent.mpkg',meshmpkgname) }); archive.finalize(); }); }); @@ -5861,7 +6136,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF meshsettings += 'MeshServer=local\r\n'; if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; } } - if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } + if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + encodeURIComponent(req.query.tag) + '\r\n'; } if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; } if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } } @@ -5999,9 +6274,47 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Setup the HTTP server without TLS obj.expressWs = require('express-ws')(obj.app, null, { wsOptions: { perMessageDeflate: (args.wscompression === true) } }); } else { + var ciphers = [ + 'TLS_AES_256_GCM_SHA384', + 'TLS_AES_128_GCM_SHA256', + 'TLS_AES_128_CCM_8_SHA256', + 'TLS_AES_128_CCM_SHA256', + 'TLS_CHACHA20_POLY1305_SHA256', + 'ECDHE-RSA-AES256-GCM-SHA384', + 'ECDHE-ECDSA-AES256-GCM-SHA384', + 'ECDHE-RSA-AES128-GCM-SHA256', + 'ECDHE-ECDSA-AES128-GCM-SHA256', + 'DHE-RSA-AES128-GCM-SHA256', + 'ECDHE-RSA-CHACHA20-POLY1305', // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8) + 'ECDHE-ARIA128-GCM-SHA256', + 'ECDHE-ARIA256-GCM-SHA384', + 'ECDHE-RSA-AES128-SHA256', // SSLlabs considers this cipher suite weak, but it's needed for older browers. + 'ECDHE-RSA-AES256-SHA384', // SSLlabs considers this cipher suite weak, but it's needed for older browers. + '!aNULL', + '!eNULL', + '!EXPORT', + '!DES', + '!RC4', + '!MD5', + '!PSK', + '!SRP', + '!CAMELLIA' + ].join(':'); + + if (obj.useNodeDefaultTLSCiphers) { + ciphers = require("tls").DEFAULT_CIPHERS; + } + + if (obj.tlsCiphers) { + ciphers = obj.tlsCiphers; + if (Array.isArray(obj.tlsCiphers)) { + ciphers = obj.tlsCiphers.join(":"); + } + } + // Setup the HTTP server with TLS, use only TLS 1.2 and higher with perfect forward secrecy (PFS). //const tlsOptions = { cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!RSA:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1 }; // This does not work with TLS 1.3 - const tlsOptions = { cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true, ciphers: "HIGH:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_CHACHA20_POLY1305_SHA256", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1 }; + const tlsOptions = { cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true, ciphers: ciphers, secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1 }; if (obj.tlsSniCredentials != null) { tlsOptions.SNICallback = TlsSniCallback; } // We have multiple web server certificate used depending on the domain name obj.tlsServer = require('https').createServer(tlsOptions, obj.app); obj.tlsServer.on('secureConnection', function () { /*console.log('tlsServer secureConnection');*/ }); @@ -6037,7 +6350,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } // Setup middleware - obj.app.engine('handlebars', obj.exphbs({ defaultLayout: false })); + obj.app.engine('handlebars', obj.exphbs.engine({ defaultLayout: false })); obj.app.set('view engine', 'handlebars'); if (obj.args.trustedproxy) { // Reverse proxy should add the "X-Forwarded-*" headers @@ -6077,9 +6390,24 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } if (obj.args.sessiontime != null) { sessionOptions.maxAge = (obj.args.sessiontime * 60000); } // sessiontime is minutes obj.app.use(require('cookie-session')(sessionOptions)); + obj.app.use(function (request, response, next) { // Patch for passport 0.6.0 - https://github.com/jaredhanson/passport/issues/904 + if (request.session && !request.session.regenerate) { + request.session.regenerate = function (cb) { + cb() + } + } + if (request.session && !request.session.save) { + request.session.save = function (cb) { + cb() + } + } + next() + }); // Handle all incoming web sockets, see if some need to be handled as web relays obj.app.ws('/*', function (ws, req, next) { + // Global error catcher + ws.on('error', function (err) { parent.debug('web', 'GENERAL WSERR: ' + err); console.log(err); }); if ((obj.webRelayRouter != null) && (obj.args.relaydns.indexOf(req.hostname) >= 0)) { handleWebRelayWebSocket(ws, req); return; } return next(); }); @@ -6213,7 +6541,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF 'Referrer-Policy': 'no-referrer', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', - 'Content-Security-Policy': "default-src 'none'; font-src 'self'; script-src 'self' 'unsafe-inline'" + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline'; frame-src 'self' mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self'" + 'Content-Security-Policy': "default-src 'none'; font-src 'self' fonts.gstatic.com data:; script-src 'self' 'unsafe-inline' " + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-src 'self' blob: mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self'; manifest-src 'self'" }; if (req.headers['user-agent'] && (req.headers['user-agent'].indexOf('Chrome') >= 0)) { headers['Permissions-Policy'] = 'interest-cohort=()'; } // Remove Google's FLoC Network, only send this if Chrome browser if ((parent.config.settings.allowframing !== true) && (typeof parent.config.settings.allowframing !== 'string')) { headers['X-Frame-Options'] = 'sameorigin'; } @@ -6250,7 +6578,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF var errlogpath = null; if (typeof parent.args.mesherrorlogpath == 'string') { errlogpath = parent.path.join(parent.args.mesherrorlogpath, 'mesherrors.txt'); } else { errlogpath = parent.getConfigFilePath('mesherrors.txt'); } parent.fs.appendFileSync(errlogpath, new Date().toLocaleString() + ': ' + `Error in res.send | ${err.code} | ${err.message} | ${res.stack}` + '\r\n'); - } catch (ex) { console.log('ERROR: Unable to write to mesherrors.txt.'); } + } catch (ex) { parent.debug('error', 'Unable to write to mesherrors.txt.'); } } }; @@ -6291,440 +6619,132 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF }); } - // Setup all sharing domains + // Setup all sharing domains and check if auth strategies need setup + var setupSSO = false for (var i in parent.config.domains) { if ((parent.config.domains[i].dns == null) && (parent.config.domains[i].share != null)) { obj.app.use(parent.config.domains[i].url, obj.express.static(parent.config.domains[i].share)); } + if (typeof parent.config.domains[i].authstrategies == 'object') { setupSSO = true }; + } + + if (setupSSO) { + setupAllDomainAuthStrategies().then(() => finalizeWebserver()); + } else { + finalizeWebserver() } // Setup all domain auth strategy passport.js - for (var i in parent.config.domains) { - if (typeof parent.config.domains[i].authstrategies == 'object') { - parent.config.domains[i].authstrategies.authStrategyFlags = 0; - const authStrategyFlags = setupDomainAuthStrategy(parent.config.domains[i]); - if (authStrategyFlags > 0) { - if (parent.config.domains[i].dns != null) { - if (typeof parent.config.domains[''].authstrategies != 'object') { parent.config.domains[''].authstrategies = { authStrategyFlags: 0 }; } - parent.config.domains[''].authstrategies.authStrategyFlags |= authStrategyFlags; - } else { - if (typeof parent.config.domains[i].authstrategies != 'object') { parent.config.domains[i].authstrategies = { authStrategyFlags: 0 }; } - parent.config.domains[i].authstrategies.authStrategyFlags |= authStrategyFlags; - } + async function setupAllDomainAuthStrategies() { + for (var i in parent.config.domains) { + if (parent.config.domains[i].dns != null) { + if (typeof parent.config.domains[''].authstrategies != 'object') { parent.config.domains[''].authstrategies = { 'authStrategyFlags': 0 }; } + parent.config.domains[''].authstrategies.authStrategyFlags |= await setupDomainAuthStrategy(parent.config.domains[i]); + } else { + if (typeof parent.config.domains[i].authstrategies != 'object') { parent.config.domains[i].authstrategies = { 'authStrategyFlags': 0 }; } + parent.config.domains[i].authstrategies.authStrategyFlags |= await setupDomainAuthStrategy(parent.config.domains[i]); } } } - - // Setup all HTTP handlers - if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req, obj.args.tlsoffload == null); }); } - for (var i in parent.config.domains) { - if ((parent.config.domains[i].dns != null) || (parent.config.domains[i].share != null)) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed. - var domain = parent.config.domains[i]; - var url = domain.url; - if (typeof domain.rootredirect == 'string') { - // Root page redirects the user to a different URL - obj.app.get(url, handleRootRedirect); - } else { - // Present the login page as the root page - obj.app.get(url, handleRootRequest); - obj.app.post(url, obj.bodyParser.urlencoded({ extended: false }), handleRootPostRequest); - } - obj.app.get(url + 'refresh.ashx', function (req, res) { res.sendStatus(200); }); - if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.backup === true))) { obj.app.get(url + 'backup.zip', handleBackupRequest); } - if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.restore === true))) { obj.app.post(url + 'restoreserver.ashx', obj.bodyParser.urlencoded({ extended: false }), handleRestoreRequest); } - obj.app.get(url + 'terms', handleTermsRequest); - obj.app.get(url + 'xterm', handleXTermRequest); - obj.app.get(url + 'login', handleRootRequest); - obj.app.post(url + 'login', obj.bodyParser.urlencoded({ extended: false }), handleRootPostRequest); - obj.app.post(url + 'tokenlogin', obj.bodyParser.urlencoded({ extended: false }), handleLoginRequest); - obj.app.get(url + 'logout', handleLogoutRequest); - obj.app.get(url + 'MeshServerRootCert.cer', handleRootCertRequest); - obj.app.post(url + 'changepassword', obj.bodyParser.urlencoded({ extended: false }), handlePasswordChangeRequest); - obj.app.post(url + 'deleteaccount', obj.bodyParser.urlencoded({ extended: false }), handleDeleteAccountRequest); - obj.app.post(url + 'createaccount', obj.bodyParser.urlencoded({ extended: false }), handleCreateAccountRequest); - obj.app.post(url + 'resetpassword', obj.bodyParser.urlencoded({ extended: false }), handleResetPasswordRequest); - obj.app.post(url + 'resetaccount', obj.bodyParser.urlencoded({ extended: false }), handleResetAccountRequest); - obj.app.get(url + 'checkmail', handleCheckMailRequest); - obj.app.get(url + 'agentinvite', handleAgentInviteRequest); - obj.app.get(url + 'userimage.ashx', handleUserImageRequest); - obj.app.post(url + 'amtevents.ashx', obj.bodyParser.urlencoded({ extended: false }), obj.handleAmtEventRequest); - obj.app.get(url + 'meshagents', obj.handleMeshAgentRequest); - obj.app.get(url + 'messenger', handleMessengerRequest); - obj.app.get(url + 'messenger.png', handleMessengerImageRequest); - obj.app.get(url + 'meshosxagent', obj.handleMeshOsxAgentRequest); - obj.app.get(url + 'meshsettings', obj.handleMeshSettingsRequest); - obj.app.get(url + 'devicepowerevents.ashx', obj.handleDevicePowerEvents); - obj.app.get(url + 'downloadfile.ashx', handleDownloadFile); - obj.app.get(url + 'commander.ashx', handleMeshCommander); - obj.app.post(url + 'uploadfile.ashx', obj.bodyParser.urlencoded({ extended: false }), handleUploadFile); - obj.app.post(url + 'uploadfilebatch.ashx', obj.bodyParser.urlencoded({ extended: false }), handleUploadFileBatch); - obj.app.post(url + 'uploadmeshcorefile.ashx', obj.bodyParser.urlencoded({ extended: false }), handleUploadMeshCoreFile); - obj.app.post(url + 'oneclickrecovery.ashx', obj.bodyParser.urlencoded({ extended: false }), handleOneClickRecoveryFile); - obj.app.get(url + 'userfiles/*', handleDownloadUserFiles); - obj.app.ws(url + 'echo.ashx', handleEchoWebSocket); - obj.app.ws(url + '2fahold.ashx', handle2faHoldWebSocket); - obj.app.ws(url + 'apf.ashx', function (ws, req) { obj.parent.mpsserver.onWebSocketConnection(ws, req); }) - obj.app.get(url + 'webrelay.ashx', function (req, res) { res.send('Websocket connection expected'); }); - obj.app.get(url + 'health.ashx', function (req, res) { res.send('ok'); }); // TODO: Perform more server checking. - obj.app.ws(url + 'webrelay.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, false, handleRelayWebSocket); }); - obj.app.ws(url + 'webider.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, false, function (ws1, req1, domain, user, cookie, authData) { obj.meshIderHandler.CreateAmtIderSession(obj, obj.db, ws1, req1, obj.args, domain, user); }); }); - obj.app.ws(url + 'control.ashx', function (ws, req) { - getWebsocketArgs(ws, req, function (ws, req) { - const domain = getDomain(req); - if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { ws.close(); return; } // Check 3FA URL key - PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { - if (user == null) { // User is not authenticated, perform inner server authentication - if (req.headers['x-meshauth'] === '*') { - PerformWSSessionInnerAuth(ws, req, domain, function (ws1, req1, domain, user) { obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws1, req1, obj.args, domain, user, authData); }); // User is authenticated - } else { - try { ws.close(); } catch (ex) { } // user is not authenticated and inner authentication was not requested, disconnect now. - } - } else { - obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws1, req1, obj.args, domain, user, authData); // User is authenticated - } - }); - }); - }); - obj.app.ws(url + 'devicefile.ashx', function (ws, req) { obj.meshDeviceFileHandler.CreateMeshDeviceFile(obj, ws, null, req, domain); }); - obj.app.get(url + 'devicefile.ashx', handleDeviceFile); - obj.app.get(url + 'agentdownload.ashx', handleAgentDownloadFile); - obj.app.get(url + 'logo.png', handleLogoRequest); - obj.app.get(url + 'loginlogo.png', handleLoginLogoRequest); - obj.app.post(url + 'translations', obj.bodyParser.urlencoded({ extended: false }), handleTranslationsRequest); - obj.app.get(url + 'welcome.jpg', handleWelcomeImageRequest); - obj.app.get(url + 'welcome.png', handleWelcomeImageRequest); - obj.app.get(url + 'recordings.ashx', handleGetRecordings); - obj.app.ws(url + 'recordings.ashx', handleGetRecordingsWebSocket); - obj.app.get(url + 'player.htm', handlePlayerRequest); - obj.app.get(url + 'player', handlePlayerRequest); - obj.app.get(url + 'sharing', handleSharingRequest); - obj.app.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler - obj.app.ws(url + 'meshrelay.ashx', function (ws, req) { - PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { - if (((parent.config.settings.desktopmultiplex === true) || (domain.desktopmultiplex === true)) && (req.query.p == 2)) { - obj.meshDesktopMultiplexHandler.CreateMeshRelay(obj, ws1, req1, domain, user, cookie); // Desktop multiplexor 1-to-n - } else { - obj.meshRelayHandler.CreateMeshRelay(obj, ws1, req1, domain, user, cookie); // Normal relay 1-to-1 - } - }); - }); - if (obj.args.wanonly != true) { // If the server is not in WAN mode, allow server relayed connections. - obj.app.ws(url + 'localrelay.ashx', function (ws, req) { - PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { - if ((user == null) || (cookie == null)) { - try { ws1.close(); } catch (ex) { } - } else { - obj.meshRelayHandler.CreateLocalRelay(obj, ws1, req1, domain, user, cookie); // Local relay - } - }); - }); - } - if (domain.agentinvitecodes == true) { - obj.app.get(url + 'invite', handleInviteRequest); - obj.app.post(url + 'invite', obj.bodyParser.urlencoded({ extended: false }), handleInviteRequest); - } + function setupHTTPHandlers() { + // Setup all HTTP handlers if (parent.pluginHandler != null) { - obj.app.get(url + 'pluginadmin.ashx', obj.handlePluginAdminReq); - obj.app.post(url + 'pluginadmin.ashx', obj.bodyParser.urlencoded({ extended: false }), obj.handlePluginAdminPostReq); - obj.app.get(url + 'pluginHandler.js', obj.handlePluginJS); + parent.pluginHandler.callHook('hook_setupHttpHandlers', obj, parent); } - - // New account CAPTCHA request - if ((domain.newaccountscaptcha != null) && (domain.newaccountscaptcha !== false)) { - obj.app.get(url + 'newAccountCaptcha.ashx', handleNewAccountCaptchaRequest); - } - - // Check CrowdSec Bounser if configured - if (parent.crowdSecBounser != null) { - obj.app.get(url + 'captcha.ashx', handleCaptchaGetRequest); - obj.app.post(url + 'captcha.ashx', obj.bodyParser.urlencoded({ extended: false }), handleCaptchaPostRequest); - } - - // Setup IP-KVM relay if supported - if (domain.ipkvm) { - obj.app.ws(url + 'ipkvm.ashx/*', function (ws, req) { - const domain = getDomain(req); - if (domain == null) { parent.debug('web', 'ipkvm: failed domain checks.'); try { ws.close(); } catch (ex) { } return; } - parent.ipKvmManager.handleIpKvmWebSocket(domain, ws, req); - }); - obj.app.get(url + 'ipkvm.ashx/*', function (req, res, next) { - const domain = getDomain(req); - if (domain == null) return; - parent.ipKvmManager.handleIpKvmGet(domain, req, res, next); - }); - } - - // Setup RDP unless indicated as disabled - if (domain.mstsc !== false) { - obj.app.get(url + 'mstsc.html', function (req, res) { handleMSTSCRequest(req, res, 'mstsc'); }); - obj.app.ws(url + 'mstscrelay.ashx', function (ws, req) { - const domain = getDomain(req); - if (domain == null) { parent.debug('web', 'mstsc: failed checks.'); try { ws.close(); } catch (e) { } return; } - // If no user is logged in and we have a default user, set it now. - if ((req.session.userid == null) && (typeof obj.args.user == 'string') && (obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()])) { req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase(); } - try { require('./apprelays.js').CreateMstscRelay(obj, obj.db, ws, req, obj.args, domain); } catch (ex) { console.log(ex); } - }); - } - - // Setup SSH if needed - if (domain.ssh === true) { - obj.app.get(url + 'ssh.html', function (req, res) { handleMSTSCRequest(req, res, 'ssh'); }); - obj.app.ws(url + 'sshrelay.ashx', function (ws, req) { - const domain = getDomain(req); - if (domain == null) { parent.debug('web', 'ssh: failed checks.'); try { ws.close(); } catch (e) { } return; } - // If no user is logged in and we have a default user, set it now. - if ((req.session.userid == null) && (typeof obj.args.user == 'string') && (obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()])) { req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase(); } - try { require('./apprelays.js').CreateSshRelay(obj, obj.db, ws, req, obj.args, domain); } catch (ex) { console.log(ex); } - }); - obj.app.ws(url + 'sshterminalrelay.ashx', function (ws, req) { - PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { - require('./apprelays.js').CreateSshTerminalRelay(obj, obj.db, ws1, req1, domain, user, cookie, obj.args); - }); - }); - obj.app.ws(url + 'sshfilesrelay.ashx', function (ws, req) { - PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { - require('./apprelays.js').CreateSshFilesRelay(obj, obj.db, ws1, req1, domain, user, cookie, obj.args); - }); - }); - } - - // Setup firebase push only server - if ((obj.parent.firebase != null) && (obj.parent.config.firebase)) { - if (obj.parent.config.firebase.pushrelayserver) { parent.debug('email', 'Firebase-pushrelay-handler'); obj.app.post(url + 'firebaserelay.aspx', obj.bodyParser.urlencoded({ extended: false }), handleFirebasePushOnlyRelayRequest); } - if (obj.parent.config.firebase.relayserver) { parent.debug('email', 'Firebase-relay-handler'); obj.app.ws(url + 'firebaserelay.aspx', handleFirebaseRelayRequest); } - } - - // Setup auth strategies using passport if needed - if (typeof domain.authstrategies == 'object') { - // Twitter - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.twitter) != 0) { - obj.app.get(url + 'auth-twitter', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('twitter-' + domain.id)(req, res, function (err) { console.log('c1', err, req.session); next(); }); - }); - obj.app.get(url + 'auth-twitter-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { - // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). - var url = req.url; - if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. - res.set('Content-Type', 'text/html'); - res.end(''); - } else { - domain.passport.authenticate('twitter-' + domain.id, { failureRedirect: '/' })(req, res, function (err) { if (err != null) { console.log(err); } next(); }); - } - }, handleStrategyLogin); - } - - // Google - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.google) != 0) { - obj.app.get(url + 'auth-google', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('google-' + domain.id, { scope: ['profile', 'email'] })(req, res, next); - }); - obj.app.get(url + 'auth-google-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('google-' + domain.id, { failureRedirect: '/' })(req, res, function (err) { if (err != null) { console.log(err); } next(); }); - }, handleStrategyLogin); - } - - // GitHub - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.github) != 0) { - obj.app.get(url + 'auth-github', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('github-' + domain.id, { scope: ['user:email'] })(req, res, next); - }); - obj.app.get(url + 'auth-github-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('github-' + domain.id, { failureRedirect: '/' })(req, res, next); - }, handleStrategyLogin); - } - - // Reddit - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.reddit) != 0) { - obj.app.get(url + 'auth-reddit', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('reddit-' + domain.id, { state: obj.parent.encodeCookie({ 'p': 'reddit' }, obj.parent.loginCookieEncryptionKey), duration: 'permanent' })(req, res, next); - }); - obj.app.get(url + 'auth-reddit-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { - // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). - var url = req.url; - if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. - res.set('Content-Type', 'text/html'); - res.end(''); - } else { - if (req.query.state != null) { - var c = obj.parent.decodeCookie(req.query.state, obj.parent.loginCookieEncryptionKey, 10); // 10 minute timeout - if ((c != null) && (c.p == 'reddit')) { domain.passport.authenticate('reddit-' + domain.id, { failureRedirect: '/' })(req, res, next); return; } - } - next(); - } - }, handleStrategyLogin); - } - - // Azure - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.azure) != 0) { - obj.app.get(url + 'auth-azure', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('azure-' + domain.id, { state: obj.parent.encodeCookie({ 'p': 'azure' }, obj.parent.loginCookieEncryptionKey) })(req, res, next); - }); - obj.app.get(url + 'auth-azure-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { - // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). - var url = req.url; - if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. - res.set('Content-Type', 'text/html'); - res.end(''); - } else { - if (req.query.state != null) { - var c = obj.parent.decodeCookie(req.query.state, obj.parent.loginCookieEncryptionKey, 10); // 10 minute timeout - if ((c != null) && (c.p == 'azure')) { domain.passport.authenticate('azure-' + domain.id, { failureRedirect: '/' })(req, res, next); return; } - } - next(); - } - }, handleStrategyLogin); - } - - // Generic OpenID Connect - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.oidc) != 0) { - obj.app.get(url + 'auth-oidc', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('oidc-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }); - obj.app.get(url + 'oidc-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('oidc-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }, handleStrategyLogin); - } - - // Generic SAML - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.saml) != 0) { - obj.app.get(url + 'auth-saml', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }); - obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }, handleStrategyLogin); - } - - // Intel SAML - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.intelSaml) != 0) { - obj.app.get(url + 'auth-intel', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }); - obj.app.post(url + 'auth-intel-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }, handleStrategyLogin); - } - - // JumpCloud SAML - if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.jumpCloudSaml) != 0) { - obj.app.get(url + 'auth-jumpcloud', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }); - obj.app.post(url + 'auth-jumpcloud-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); - }, handleStrategyLogin); - } - } - - // Server redirects - if (parent.config.domains[i].redirects) { for (var j in parent.config.domains[i].redirects) { if (j[0] != '_') { obj.app.get(url + j, obj.handleDomainRedirect); } } } - - // Server picture - obj.app.get(url + 'serverpic.ashx', function (req, res) { - // Check if we have "server.jpg" in the data folder, if so, use that. - if ((parent.configurationFiles != null) && (parent.configurationFiles['server.png'] != null)) { - res.set({ 'Content-Type': 'image/png' }); - res.send(parent.configurationFiles['server.png']); + if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req, obj.args.tlsoffload == null); }); } + for (var i in parent.config.domains) { + if ((parent.config.domains[i].dns != null) || (parent.config.domains[i].share != null)) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed. + var domain = parent.config.domains[i]; + var url = domain.url; + if (typeof domain.rootredirect == 'string') { + // Root page redirects the user to a different URL + obj.app.get(url, handleRootRedirect); } else { - // Check if we have "server.jpg" in the data folder, if so, use that. - var p = obj.path.join(obj.parent.datapath, 'server.png'); - if (obj.fs.existsSync(p)) { - // Use the data folder server picture - try { res.sendFile(p); } catch (ex) { res.sendStatus(404); } - } else { - var domain = getDomain(req); - if ((domain != null) && (domain.webpublicpath != null) && (obj.fs.existsSync(obj.path.join(domain.webpublicpath, 'images/server-256.png')))) { - // Use the domain server picture - try { res.sendFile(obj.path.join(domain.webpublicpath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); } - } else if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png'))) { - // Use the override server picture - try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); } - } else { - // Use the default server picture - try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); } - } - } + // Present the login page as the root page + obj.app.get(url, handleRootRequest); + obj.app.post(url, obj.bodyParser.urlencoded({ extended: false }), handleRootPostRequest); } - }); - - // Receive mesh agent connections - obj.app.ws(url + 'agent.ashx', function (ws, req) { - var domain = checkAgentIpAddress(ws, req); - if (domain == null) { parent.debug('web', 'Got agent connection with bad domain or blocked IP address ' + req.clientIp + ', holding.'); return; } - if (domain.agentkey && ((req.query.key == null) || (domain.agentkey.indexOf(req.query.key) == -1))) { return; } // If agent key is required and not provided or not valid, just hold the websocket and do nothing. - //console.log('Agent connect: ' + req.clientIp); - try { obj.meshAgentHandler.CreateMeshAgent(obj, obj.db, ws, req, obj.args, domain); } catch (e) { console.log(e); } - }); - - // Setup MQTT broker over websocket - if (obj.parent.mqttbroker != null) { - obj.app.ws(url + 'mqtt.ashx', function (ws, req) { - var domain = checkAgentIpAddress(ws, req); - if (domain == null) { parent.debug('web', 'Got agent connection with bad domain or blocked IP address ' + req.clientIp + ', holding.'); return; } - var serialtunnel = SerialTunnel(); - serialtunnel.xtransport = 'ws'; - serialtunnel.xdomain = domain; - serialtunnel.xip = req.clientIp; - ws.on('message', function (b) { serialtunnel.updateBuffer(Buffer.from(b, 'binary')) }); - serialtunnel.forwardwrite = function (b) { ws.send(b, 'binary') } - ws.on('close', function () { serialtunnel.emit('end'); }); - obj.parent.mqttbroker.handle(serialtunnel); // Pass socket wrapper to MQTT broker + obj.app.get(url + 'refresh.ashx', function (req, res) { res.sendStatus(200); }); + if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.backup === true))) { obj.app.get(url + 'backup.zip', handleBackupRequest); } + if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.restore === true))) { obj.app.post(url + 'restoreserver.ashx', obj.bodyParser.urlencoded({ extended: false }), handleRestoreRequest); } + obj.app.get(url + 'terms', handleTermsRequest); + obj.app.get(url + 'xterm', handleXTermRequest); + obj.app.get(url + 'login', handleRootRequest); + obj.app.post(url + 'login', obj.bodyParser.urlencoded({ extended: false }), handleRootPostRequest); + obj.app.post(url + 'tokenlogin', obj.bodyParser.urlencoded({ extended: false }), handleLoginRequest); + obj.app.get(url + 'logout', handleLogoutRequest); + obj.app.get(url + 'MeshServerRootCert.cer', handleRootCertRequest); + obj.app.get(url + 'manifest.json', handleManifestRequest); + obj.app.post(url + 'changepassword', obj.bodyParser.urlencoded({ extended: false }), handlePasswordChangeRequest); + obj.app.post(url + 'deleteaccount', obj.bodyParser.urlencoded({ extended: false }), handleDeleteAccountRequest); + obj.app.post(url + 'createaccount', obj.bodyParser.urlencoded({ extended: false }), handleCreateAccountRequest); + obj.app.post(url + 'resetpassword', obj.bodyParser.urlencoded({ extended: false }), handleResetPasswordRequest); + obj.app.post(url + 'resetaccount', obj.bodyParser.urlencoded({ extended: false }), handleResetAccountRequest); + obj.app.get(url + 'checkmail', handleCheckMailRequest); + obj.app.get(url + 'agentinvite', handleAgentInviteRequest); + obj.app.get(url + 'userimage.ashx', handleUserImageRequest); + obj.app.post(url + 'amtevents.ashx', obj.bodyParser.urlencoded({ extended: false }), obj.handleAmtEventRequest); + obj.app.get(url + 'meshagents', obj.handleMeshAgentRequest); + obj.app.get(url + 'messenger', handleMessengerRequest); + obj.app.get(url + 'messenger.png', handleMessengerImageRequest); + obj.app.get(url + 'meshosxagent', obj.handleMeshOsxAgentRequest); + obj.app.get(url + 'meshsettings', obj.handleMeshSettingsRequest); + obj.app.get(url + 'devicepowerevents.ashx', obj.handleDevicePowerEvents); + obj.app.get(url + 'downloadfile.ashx', handleDownloadFile); + obj.app.get(url + 'commander.ashx', handleMeshCommander); + obj.app.post(url + 'uploadfile.ashx', obj.bodyParser.urlencoded({ extended: false }), handleUploadFile); + obj.app.post(url + 'uploadfilebatch.ashx', obj.bodyParser.urlencoded({ extended: false }), handleUploadFileBatch); + obj.app.post(url + 'uploadmeshcorefile.ashx', obj.bodyParser.urlencoded({ extended: false }), handleUploadMeshCoreFile); + obj.app.post(url + 'oneclickrecovery.ashx', obj.bodyParser.urlencoded({ extended: false }), handleOneClickRecoveryFile); + obj.app.get(url + 'userfiles/*', handleDownloadUserFiles); + obj.app.ws(url + 'echo.ashx', handleEchoWebSocket); + obj.app.ws(url + '2fahold.ashx', handle2faHoldWebSocket); + obj.app.ws(url + 'apf.ashx', function (ws, req) { obj.parent.mpsserver.onWebSocketConnection(ws, req); }) + obj.app.get(url + 'webrelay.ashx', function (req, res) { res.send('Websocket connection expected'); }); + obj.app.get(url + 'health.ashx', function (req, res) { res.send('ok'); }); // TODO: Perform more server checking. + obj.app.ws(url + 'webrelay.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, false, handleRelayWebSocket); }); + obj.app.ws(url + 'webider.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, false, function (ws1, req1, domain, user, cookie, authData) { obj.meshIderHandler.CreateAmtIderSession(obj, obj.db, ws1, req1, obj.args, domain, user); }); }); + obj.app.ws(url + 'control.ashx', function (ws, req) { + getWebsocketArgs(ws, req, function (ws, req) { + const domain = getDomain(req); + if (obj.CheckWebServerOriginName(domain, req) == false) { + try { ws.send(JSON.stringify({ action: 'close', cause: 'invalidorigin', msg: 'invalidorigin' })); } catch (ex) { } + try { ws.close(); } catch (ex) { } + return; + } + if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { // Check 3FA URL key + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'nokey' })); } catch (ex) { } + try { ws.close(); } catch (ex) { } + return; + } + PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { + if (user == null) { // User is not authenticated, perform inner server authentication + if (req.headers['x-meshauth'] === '*') { + PerformWSSessionInnerAuth(ws, req, domain, function (ws1, req1, domain, user) { obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws1, req1, obj.args, domain, user, authData); }); // User is authenticated + } else { + try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth' })); } catch (ex) { } + try { ws.close(); } catch (ex) { } // user is not authenticated and inner authentication was not requested, disconnect now. + } + } else { + obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws1, req1, obj.args, domain, user, authData); // User is authenticated + } + }); + }); }); - } - - // Setup any .well-known folders - var p = obj.parent.path.join(obj.parent.datapath, '.well-known' + ((parent.config.domains[i].id == '') ? '' : ('-' + parent.config.domains[i].id))); - if (obj.parent.fs.existsSync(p)) { obj.app.use(url + '.well-known', obj.express.static(p)); } - - // Setup the alternative agent-only port - if (obj.agentapp) { - // Receive mesh agent connections on alternate port - obj.agentapp.ws(url + 'agent.ashx', function (ws, req) { - var domain = checkAgentIpAddress(ws, req); - if (domain == null) { parent.debug('web', 'Got agent connection with bad domain or blocked IP address ' + req.clientIp + ', holding.'); return; } - if (domain.agentkey && ((req.query.key == null) || (domain.agentkey.indexOf(req.query.key) == -1))) { return; } // If agent key is required and not provided or not valid, just hold the websocket and do nothing. - try { obj.meshAgentHandler.CreateMeshAgent(obj, obj.db, ws, req, obj.args, domain); } catch (e) { console.log(e); } - }); - - // Setup mesh relay on alternative agent-only port - obj.agentapp.ws(url + 'meshrelay.ashx', function (ws, req) { + obj.app.ws(url + 'devicefile.ashx', function (ws, req) { obj.meshDeviceFileHandler.CreateMeshDeviceFile(obj, ws, null, req, domain); }); + obj.app.get(url + 'devicefile.ashx', handleDeviceFile); + obj.app.get(url + 'agentdownload.ashx', handleAgentDownloadFile); + obj.app.get(url + 'logo.png', handleLogoRequest); + obj.app.get(url + 'loginlogo.png', handleLoginLogoRequest); + obj.app.get(url + 'pwalogo.png', handlePWALogoRequest); + obj.app.post(url + 'translations', obj.bodyParser.urlencoded({ extended: false }), handleTranslationsRequest); + obj.app.get(url + 'welcome.jpg', handleWelcomeImageRequest); + obj.app.get(url + 'welcome.png', handleWelcomeImageRequest); + obj.app.get(url + 'recordings.ashx', handleGetRecordings); + obj.app.ws(url + 'recordings.ashx', handleGetRecordingsWebSocket); + obj.app.get(url + 'player.htm', handlePlayerRequest); + obj.app.get(url + 'player', handlePlayerRequest); + obj.app.get(url + 'sharing', handleSharingRequest); + obj.app.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler + obj.app.ws(url + 'meshrelay.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { if (((parent.config.settings.desktopmultiplex === true) || (domain.desktopmultiplex === true)) && (req.query.p == 2)) { obj.meshDesktopMultiplexHandler.CreateMeshRelay(obj, ws1, req1, domain, user, cookie); // Desktop multiplexor 1-to-n @@ -6733,224 +6753,702 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } }); }); + if (obj.args.wanonly != true) { // If the server is not in WAN mode, allow server relayed connections. + obj.app.ws(url + 'localrelay.ashx', function (ws, req) { + PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { + if ((user == null) || (cookie == null)) { + try { ws1.close(); } catch (ex) { } + } else { + obj.meshRelayHandler.CreateLocalRelay(obj, ws1, req1, domain, user, cookie); // Local relay + } + }); + }); + } + obj.app.get(url + 'invite', handleInviteRequest); + obj.app.post(url + 'invite', obj.bodyParser.urlencoded({ extended: false }), handleInviteRequest); + + if (parent.pluginHandler != null) { + obj.app.get(url + 'pluginadmin.ashx', obj.handlePluginAdminReq); + obj.app.post(url + 'pluginadmin.ashx', obj.bodyParser.urlencoded({ extended: false }), obj.handlePluginAdminPostReq); + obj.app.get(url + 'pluginHandler.js', obj.handlePluginJS); + } - // Allows agents to transfer files - obj.agentapp.ws(url + 'devicefile.ashx', function (ws, req) { obj.meshDeviceFileHandler.CreateMeshDeviceFile(obj, ws, null, req, domain); }); + // New account CAPTCHA request + if ((domain.newaccountscaptcha != null) && (domain.newaccountscaptcha !== false)) { + obj.app.get(url + 'newAccountCaptcha.ashx', handleNewAccountCaptchaRequest); + } - // Setup agent to/from server file transfer handler - obj.agentapp.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler + // Check CrowdSec Bounser if configured + if (parent.crowdSecBounser != null) { + obj.app.get(url + 'captcha.ashx', handleCaptchaGetRequest); + obj.app.post(url + 'captcha.ashx', obj.bodyParser.urlencoded({ extended: false }), handleCaptchaPostRequest); + } - // Setup agent downloads for meshcore updates - obj.agentapp.get(url + 'meshagents', obj.handleMeshAgentRequest); - } + // Setup IP-KVM relay if supported + if (domain.ipkvm) { + obj.app.ws(url + 'ipkvm.ashx/*', function (ws, req) { + const domain = getDomain(req); + if (domain == null) { parent.debug('web', 'ipkvm: failed domain checks.'); try { ws.close(); } catch (ex) { } return; } + parent.ipKvmManager.handleIpKvmWebSocket(domain, ws, req); + }); + obj.app.get(url + 'ipkvm.ashx/*', function (req, res, next) { + const domain = getDomain(req); + if (domain == null) return; + parent.ipKvmManager.handleIpKvmGet(domain, req, res, next); + }); + } - // Setup web relay on this web server if needed - // We set this up when a DNS name is used as a web relay instead of a port - if (obj.args.relaydns != null) { - obj.webRelayRouter = require('express').Router(); + // Setup RDP unless indicated as disabled + if (domain.mstsc !== false) { + obj.app.get(url + 'mstsc.html', function (req, res) { handleMSTSCRequest(req, res, 'mstsc'); }); + obj.app.ws(url + 'mstscrelay.ashx', function (ws, req) { + const domain = getDomain(req); + if (domain == null) { parent.debug('web', 'mstsc: failed checks.'); try { ws.close(); } catch (e) { } return; } + // If no user is logged in and we have a default user, set it now. + if ((req.session.userid == null) && (typeof obj.args.user == 'string') && (obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()])) { req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase(); } + try { require('./apprelays.js').CreateMstscRelay(obj, obj.db, ws, req, obj.args, domain); } catch (ex) { console.log(ex); } + }); + } - // This is the magic URL that will setup the relay session - obj.webRelayRouter.get('/control-redirect.ashx', function (req, res, next) { - if (obj.args.relaydns.indexOf(req.hostname) == -1) { res.sendStatus(404); return; } - if ((req.session.userid == null) && obj.args.user && obj.users['user//' + obj.args.user.toLowerCase()]) { req.session.userid = 'user//' + obj.args.user.toLowerCase(); } // Use a default user if needed - res.set({ 'Cache-Control': 'no-store' }); - parent.debug('web', 'webRelaySetup'); + // Setup SSH if needed + if (domain.ssh === true) { + obj.app.get(url + 'ssh.html', function (req, res) { handleMSTSCRequest(req, res, 'ssh'); }); + obj.app.ws(url + 'sshrelay.ashx', function (ws, req) { + const domain = getDomain(req); + if (domain == null) { parent.debug('web', 'ssh: failed checks.'); try { ws.close(); } catch (e) { } return; } + // If no user is logged in and we have a default user, set it now. + if ((req.session.userid == null) && (typeof obj.args.user == 'string') && (obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()])) { req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase(); } + try { require('./apprelays.js').CreateSshRelay(obj, obj.db, ws, req, obj.args, domain); } catch (ex) { console.log(ex); } + }); + obj.app.ws(url + 'sshterminalrelay.ashx', function (ws, req) { + PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { + require('./apprelays.js').CreateSshTerminalRelay(obj, obj.db, ws1, req1, domain, user, cookie, obj.args); + }); + }); + obj.app.ws(url + 'sshfilesrelay.ashx', function (ws, req) { + PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { + require('./apprelays.js').CreateSshFilesRelay(obj, obj.db, ws1, req1, domain, user, cookie, obj.args); + }); + }); + } - // Decode the relay cookie - if (req.query.c == null) { res.sendStatus(404); return; } + // Setup firebase push only server + if ((obj.parent.firebase != null) && (obj.parent.config.firebase)) { + if (obj.parent.config.firebase.pushrelayserver) { parent.debug('email', 'Firebase-pushrelay-handler'); obj.app.post(url + 'firebaserelay.aspx', obj.bodyParser.urlencoded({ extended: false }), handleFirebasePushOnlyRelayRequest); } + if (obj.parent.config.firebase.relayserver) { parent.debug('email', 'Firebase-relay-handler'); obj.app.ws(url + 'firebaserelay.aspx', handleFirebaseRelayRequest); } + } - // Decode and check if this relay cookie is valid - var userid, domainid, domain, nodeid, addr, port, appid, webSessionId, expire, publicid; - const urlCookie = obj.parent.decodeCookie(req.query.c, parent.loginCookieEncryptionKey, 32); // Allow cookies up to 32 minutes old. The web page will renew this cookie every 30 minutes. - if (urlCookie == null) { res.sendStatus(404); return; } - - // Decode the incoming cookie - if ((urlCookie.ruserid != null) && (urlCookie.x != null)) { - if (parent.webserver.destroyedSessions[urlCookie.ruserid + '/' + urlCookie.x] != null) { res.sendStatus(404); return; } - - // This is a standard user, figure out what our web relay will be. - if (req.session.x != urlCookie.x) { req.session.x = urlCookie.x; } // Set the sessionid if missing - if (req.session.userid != urlCookie.ruserid) { req.session.userid = urlCookie.ruserid; } // Set the session userid if missing - if (req.session.z) { delete req.session.z; } // Clear the web relay guest session - userid = req.session.userid; - domainid = userid.split('/')[1]; - domain = parent.config.domains[domainid]; - nodeid = ((req.query.relayid != null) ? req.query.relayid : req.query.n); - addr = (req.query.addr != null) ? req.query.addr : '127.0.0.1'; - port = parseInt(req.query.p); - appid = parseInt(req.query.appid); - webSessionId = req.session.userid + '/' + req.session.x; - - // Check that all the required arguments are present - if ((req.session.userid == null) || (req.session.x == null) || (req.query.n == null) || (req.query.p == null) || (parent.webserver.destroyedSessions[webSessionId] != null) || ((req.query.appid != 1) && (req.query.appid != 2))) { res.redirect('/'); return; } - } else if (urlCookie.r == 8) { - // This is a guest user, figure out what our web relay will be. - userid = urlCookie.userid; - domainid = userid.split('/')[1]; - domain = parent.config.domains[domainid]; - nodeid = urlCookie.nid; - addr = (urlCookie.addr != null) ? urlCookie.addr : '127.0.0.1'; - port = urlCookie.port; - appid = (urlCookie.p == 16) ? 2 : 1; // appid: 1 = HTTP, 2 = HTTPS - webSessionId = userid + '/' + urlCookie.pid; - publicid = urlCookie.pid; - if (req.session.x) { delete req.session.x; } // Clear the web relay sessionid - if (req.session.userid) { delete req.session.userid; } // Clear the web relay userid - if (req.session.z != webSessionId) { req.session.z = webSessionId; } // Set the web relay guest session - expire = urlCookie.expire; - if ((expire != null) && (expire <= Date.now())) { parent.debug('webrelay', 'expired link'); res.sendStatus(404); return; } + // Setup auth strategies using passport if needed + if (typeof domain.authstrategies == 'object') { + parent.authLog('setupHTTPHandlers', `Setting up authentication strategies login and callback URLs for ${domain.id == '' ? 'root' : '"' + domain.id + '"'} domain.`); + // Twitter + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.twitter) != 0) { + obj.app.get(url + 'auth-twitter', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('twitter-' + domain.id)(req, res, function (err) { console.log('c1', err, req.session); next(); }); + }); + obj.app.get(url + 'auth-twitter-callback', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { + // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). + var url = req.url; + if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. + res.set('Content-Type', 'text/html'); + res.end(''); + } else { + domain.passport.authenticate('twitter-' + domain.id, { failureRedirect: domain.url })(req, res, function (err) { if (err != null) { console.log(err); } next(); }); + } + }, handleStrategyLogin); } - // No session identifier was setup, exit now - if (webSessionId == null) { res.sendStatus(404); return; } + // Google + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.google) != 0) { + obj.app.get(url + 'auth-google', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('google-' + domain.id, { scope: ['profile', 'email'] })(req, res, next); + }); + obj.app.get(url + 'auth-google-callback', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('google-' + domain.id, { failureRedirect: domain.url })(req, res, function (err) { if (err != null) { console.log(err); } next(); }); + }, handleStrategyLogin); + } - // Check that we have an exact session on any of the relay DNS names - var xrelaySessionId, xrelaySession, freeRelayHost, oldestRelayTime, oldestRelayHost; - for (var hostIndex in obj.args.relaydns) { - const host = obj.args.relaydns[hostIndex]; - xrelaySessionId = webSessionId + '/' + host; - xrelaySession = webRelaySessions[xrelaySessionId]; - if (xrelaySession == null) { - // We found an unused hostname, save this as it could be useful. - if (freeRelayHost == null) { freeRelayHost = host; } + // GitHub + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.github) != 0) { + obj.app.get(url + 'auth-github', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('github-' + domain.id, { scope: ['user:email'] })(req, res, next); + }); + obj.app.get(url + 'auth-github-callback', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('github-' + domain.id, { failureRedirect: domain.url })(req, res, next); + }, handleStrategyLogin); + } + + // Azure + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.azure) != 0) { + obj.app.get(url + 'auth-azure', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('azure-' + domain.id, { state: obj.parent.encodeCookie({ 'p': 'azure' }, obj.parent.loginCookieEncryptionKey) })(req, res, next); + }); + obj.app.get(url + 'auth-azure-callback', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { + // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). + var url = req.url; + if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. + res.set('Content-Type', 'text/html'); + res.end(''); + } else { + if (req.query.state != null) { + var c = obj.parent.decodeCookie(req.query.state, obj.parent.loginCookieEncryptionKey, 10); // 10 minute timeout + if ((c != null) && (c.p == 'azure')) { domain.passport.authenticate('azure-' + domain.id, { failureRedirect: domain.url })(req, res, next); return; } + } + next(); + } + }, handleStrategyLogin); + } + + // Setup OpenID Connect URLs + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.oidc) != 0) { + let authURL = url + 'auth-oidc' + parent.authLog('setupHTTPHandlers', `OIDC: Authorization URL: ${authURL}`); + obj.app.get(authURL, function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate(`oidc-${domain.id}`, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }); + let redirectPath; + if (typeof domain.authstrategies.oidc.client.redirect_uri == 'string') { + redirectPath = (new URL(domain.authstrategies.oidc.client.redirect_uri)).pathname; + } else if (Array.isArray(domain.authstrategies.oidc.client.redirect_uris)) { + redirectPath = (new URL(domain.authstrategies.oidc.client.redirect_uris[0])).pathname; } else { - // Check if we already have a relay session that matches exactly what we want - if ((xrelaySession.domain.id == domain.id) && (xrelaySession.userid == userid) && (xrelaySession.nodeid == nodeid) && (xrelaySession.addr == addr) && (xrelaySession.port == port) && (xrelaySession.appid == appid)) { - // We found an exact match, we are all setup already, redirect to root of that DNS name - if (host == req.hostname) { - // Request was made on the same host, redirect to root. - res.redirect('/'); + redirectPath = url + 'auth-oidc-callback'; + } + parent.authLog('setupHTTPHandlers', `OIDC: Callback URL: ${redirectPath}`); + obj.app.get(redirectPath, obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + if (req.session && req.session.userid) { next(); return; } // already logged in so dont authenticate just carry on + if (req.session && req.session['oidc-' + domain.id]) { // we have a request to login so do authenticate + domain.passport.authenticate(`oidc-${domain.id}`, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + } else { // no idea so carry on + next(); return; + } + }, handleStrategyLogin); + } + + // Generic SAML + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.saml) != 0) { + obj.app.get(url + 'auth-saml', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + //set RelayState when queries are passed + if (Object.keys(req.query).length != 0){ + req.query.RelayState = encodeURIComponent(`${req.protocol}://${req.hostname}${req.originalUrl}`.replace('auth-saml/','')) + } + domain.passport.authenticate('saml-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }); + obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('saml-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }, handleStrategyLogin); + } + + // Intel SAML + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.intelSaml) != 0) { + obj.app.get(url + 'auth-intel', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }); + obj.app.post(url + 'auth-intel-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }, handleStrategyLogin); + } + + // JumpCloud SAML + if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.jumpCloudSaml) != 0) { + obj.app.get(url + 'auth-jumpcloud', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }); + obj.app.post(url + 'auth-jumpcloud-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next); + }, handleStrategyLogin); + } + } + + // Setup Duo HTTP handlers if supported + if ((typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) { + // Duo authentication handler + obj.app.get(url + 'auth-duo', function (req, res){ + var domain = getDomain(req); + const sec = parent.decryptSessionData(req.session.e); + if ((req.query.state !== sec.duostate) || (req.query.duo_code == null)) { + // The state returned from Duo is not the same as what was in the session, so must fail + parent.debug('web', 'handleRootRequest: Duo 2FA state failed.'); + req.session.loginmode = 1; + req.session.messageid = 117; // Invalid security check + res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page + return; + } else { + // User credentials are stored in session, just check again and get userid + obj.authenticate(sec.tuser, sec.tpass, domain, function (err, userid, passhint, loginOptions) { + if ((userid != null) && (err == null)) { + // Login data correct, now exchange authorization code for 2FA + const duo = require('@duosecurity/duo_universal'); + const client = new duo.Client({ + clientId: domain.duo2factor.integrationkey, + clientSecret: domain.duo2factor.secretkey, + apiHost: domain.duo2factor.apihostname, + redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('?key=' + domain.loginkey) : '') + }); + client.exchangeAuthorizationCodeFor2FAResult(req.query.duo_code, userid.split('/')[2]).then(function (data) { + const sec = parent.decryptSessionData(req.session.e); + if ((sec != null) && (sec.duoconfig == 1)) { + // Duo 2FA exchange success + parent.debug('web', 'handleRootRequest: Duo 2FA configuration success.'); + + // Enable Duo for this user + var user = obj.users[userid]; + if (user.otpduo == null) { + user.otpduo = {}; + db.SetUser(user); + + // Notify change + var targets = ['*', 'server-users', user._id]; + if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } } + var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msgid: 160, msg: "Enabled duo two-factor authentication.", domain: domain.id }; + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come. + parent.DispatchEvent(targets, obj, event); + } + + // Clear the Duo state + delete sec.duostate; + delete sec.duoconfig; + req.session.e = parent.encryptSessionData(sec); + + var url = req.session.duorurl; + delete req.session.duorurl; + res.redirect(url ? url : domain.url); // Redirect back to the user's original page + } else { + // Duo 2FA exchange success + parent.debug('web', 'handleRootRequest: Duo 2FA authorization success.'); + req.session.userid = userid; + delete req.session.currentNode; + req.session.ip = req.clientIp; // Bind this session to the IP address of the request + setSessionRandom(req); + + // Clear the Duo state + delete sec.duostate; + req.session.e = parent.encryptSessionData(sec); + + obj.parent.authLog('https', 'Accepted Duo authentication for ' + userid + ' from ' + req.clientIp + ':' + req.connection.remotePort, { useragent: req.headers['user-agent'], sessionid: req.session.x }); + res.redirect(domain.url + getQueryPortion(req)); + } + }).catch(function (err) { + console.log('err', err); + const sec = parent.decryptSessionData(req.session.e); + if ((sec != null) && (sec.duoconfig == 1)) { + // Duo 2FA exchange success + parent.debug('web', 'handleRootRequest: Duo 2FA configuration failed.'); + + // Clear the Duo state + delete sec.duostate; + delete sec.duoconfig; + req.session.e = parent.encryptSessionData(sec); + + var url = req.session.duorurl; + delete req.session.duorurl; + res.redirect(url ? url : domain.url); // Redirect back to the user's original page + } else { + // Duo 2FA exchange failed + parent.debug('web', 'handleRootRequest: Duo 2FA authorization failed.'); + + // Clear the Duo state + delete sec.duostate; + req.session.e = parent.encryptSessionData(sec); + + req.session.loginmode = 1; + req.session.messageid = 117; // Invalid security check + res.redirect(domain.url + getQueryPortion(req)); + } + }); } else { - // Request was made to a different host - const httpport = ((args.aliasport != null) ? args.aliasport : args.port); - res.redirect('https://' + host + ((httpport != 443) ? (':' + httpport) : '') + '/'); + // Login failed + parent.debug('web', 'handleRootRequest: login authorization failed when returning from Duo 2FA.'); + req.session.loginmode = 1; + res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page + return; } - return; - } - - // Keep a record of the oldest web relay session, this could be useful. - if (oldestRelayHost == null) { - // Oldest host not set yet, set it - oldestRelayHost = host; - oldestRelayTime = xrelaySession.lastOperation; - } else { - // Check if this host is older then oldest so far - if (oldestRelayTime > xrelaySession.lastOperation) { - oldestRelayHost = host; - oldestRelayTime = xrelaySession.lastOperation; - } - } - } - } - - // Check that the user has rights to access this device - parent.webserver.GetNodeWithRights(domain, userid, nodeid, function (node, rights, visible) { - // If there is no remote control or relay rights, reject this web relay - if ((rights & 0x00200008) == 0) { res.sendStatus(404); return; } // MESHRIGHT_REMOTECONTROL or MESHRIGHT_RELAY - - // Check if there is a free relay DNS name we can use - var selectedHost = null; - if (freeRelayHost != null) { - // There is a free one, use it. - selectedHost = freeRelayHost; - } else { - // No free ones, close the oldest one - selectedHost = oldestRelayHost; - } - xrelaySessionId = webSessionId + '/' + selectedHost; - - if (selectedHost == req.hostname) { - // If this web relay session id is not free, close it now - xrelaySession = webRelaySessions[xrelaySessionId]; - if (xrelaySession != null) { xrelaySession.close(); delete webRelaySessions[xrelaySessionId]; } - - // Create a web relay session - const relaySession = require('./apprelays.js').CreateWebRelaySession(obj, db, req, args, domain, userid, nodeid, addr, port, appid, xrelaySessionId, expire, node.mtype); - relaySession.xpublicid = publicid; - relaySession.onclose = function (sessionId) { - // Remove the relay session - delete webRelaySessions[sessionId]; - // If there are not more relay sessions, clear the cleanup timer - if ((Object.keys(webRelaySessions).length == 0) && (obj.cleanupTimer != null)) { clearInterval(webRelayCleanupTimer); obj.cleanupTimer = null; } - } - - // Set the multi-tunnel session - webRelaySessions[xrelaySessionId] = relaySession; - - // Setup the cleanup timer if needed - if (obj.cleanupTimer == null) { webRelayCleanupTimer = setInterval(checkWebRelaySessionsTimeout, 10000); } - - // Redirect to root. - res.redirect('/'); - } else { - if (req.query.noredirect != null) { - // No redirects allowed, fail here. This is important to make sure there is no redirect cascades - res.sendStatus(404); - } else { - // Request was made to a different host, redirect using the full URL so an HTTP cookie can be created on the other DNS name. - const httpport = ((args.aliasport != null) ? args.aliasport : args.port); - res.redirect('https://' + selectedHost + ((httpport != 443) ? (':' + httpport) : '') + req.url + '&noredirect=1'); - } + }); } }); + + // Configure Duo handler + obj.app.get(url + 'add-duo', function (req, res) { + var domain = getDomain(req); + const sec = parent.decryptSessionData(req.session.e); + + if (req.session.userid == null) { + res.sendStatus(404); + } else { + // Redirect to Duo here + const duo = require('@duosecurity/duo_universal'); + const client = new duo.Client({ + clientId: domain.duo2factor.integrationkey, + clientSecret: domain.duo2factor.secretkey, + apiHost: domain.duo2factor.apihostname, + redirectUrl: obj.generateBaseURL(domain, req) + 'auth-duo' + (domain.loginkey != null ? ('&key=' + domain.loginkey) : '') + }); + + // Setup the Duo configuration + if (req.query.rurl) { req.session.duorurl = req.query.rurl; } // Set Duo return URL + const sec = parent.decryptSessionData(req.session.e); + sec.duostate = client.generateState(); + sec.duoconfig = 1; + req.session.e = parent.encryptSessionData(sec); + parent.debug('web', 'Redirecting user ' + req.session.userid + ' to Duo for configuration'); + res.redirect(client.createAuthUrl(req.session.userid.split('/')[2], sec.duostate)); + } + }); + } + + // Server redirects + if (parent.config.domains[i].redirects) { for (var j in parent.config.domains[i].redirects) { if (j[0] != '_') { obj.app.get(url + j, obj.handleDomainRedirect); } } } + + // Server picture + obj.app.get(url + 'serverpic.ashx', function (req, res) { + // Check if we have "server.jpg" in the data folder, if so, use that. + if ((parent.configurationFiles != null) && (parent.configurationFiles['server.png'] != null)) { + res.set({ 'Content-Type': 'image/png' }); + res.send(parent.configurationFiles['server.png']); + } else { + // Check if we have "server.jpg" in the data folder, if so, use that. + var p = obj.path.join(obj.parent.datapath, 'server.png'); + if (obj.fs.existsSync(p)) { + // Use the data folder server picture + try { res.sendFile(p); } catch (ex) { res.sendStatus(404); } + } else { + var domain = getDomain(req); + if ((domain != null) && (domain.webpublicpath != null) && (obj.fs.existsSync(obj.path.join(domain.webpublicpath, 'images/server-256.png')))) { + // Use the domain server picture + try { res.sendFile(obj.path.join(domain.webpublicpath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); } + } else if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png'))) { + // Use the override server picture + try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); } + } else { + // Use the default server picture + try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); } + } + } + } }); - // Handle all incoming requests as web relays - obj.webRelayRouter.get('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + // Receive mesh agent connections + obj.app.ws(url + 'agent.ashx', function (ws, req) { + var domain = checkAgentIpAddress(ws, req); + if (domain == null) { parent.debug('web', 'Got agent connection with bad domain or blocked IP address ' + req.clientIp + ', holding.'); return; } + if (domain.agentkey && ((req.query.key == null) || (domain.agentkey.indexOf(req.query.key) == -1))) { return; } // If agent key is required and not provided or not valid, just hold the websocket and do nothing. + //console.log('Agent connect: ' + req.clientIp); + try { obj.meshAgentHandler.CreateMeshAgent(obj, obj.db, ws, req, obj.args, domain); } catch (ex) { console.log(ex); } + }); - // Handle all incoming requests as web relays - obj.webRelayRouter.post('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + // Setup MQTT broker over websocket + if (obj.parent.mqttbroker != null) { + obj.app.ws(url + 'mqtt.ashx', function (ws, req) { + var domain = checkAgentIpAddress(ws, req); + if (domain == null) { parent.debug('web', 'Got agent connection with bad domain or blocked IP address ' + req.clientIp + ', holding.'); return; } + var serialtunnel = SerialTunnel(); + serialtunnel.xtransport = 'ws'; + serialtunnel.xdomain = domain; + serialtunnel.xip = req.clientIp; + ws.on('message', function (b) { serialtunnel.updateBuffer(Buffer.from(b, 'binary')) }); + serialtunnel.forwardwrite = function (b) { ws.send(b, 'binary') } + ws.on('close', function () { serialtunnel.emit('end'); }); + obj.parent.mqttbroker.handle(serialtunnel); // Pass socket wrapper to MQTT broker + }); + } - // Handle all incoming requests as web relays - obj.webRelayRouter.put('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + // Setup any .well-known folders + var p = obj.parent.path.join(obj.parent.datapath, '.well-known' + ((parent.config.domains[i].id == '') ? '' : ('-' + parent.config.domains[i].id))); + if (obj.parent.fs.existsSync(p)) { obj.app.use(url + '.well-known', obj.express.static(p)); } - // Handle all incoming requests as web relays - obj.webRelayRouter.delete('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + // Setup the alternative agent-only port + if (obj.agentapp) { + // Receive mesh agent connections on alternate port + obj.agentapp.ws(url + 'agent.ashx', function (ws, req) { + var domain = checkAgentIpAddress(ws, req); + if (domain == null) { parent.debug('web', 'Got agent connection with bad domain or blocked IP address ' + req.clientIp + ', holding.'); return; } + if (domain.agentkey && ((req.query.key == null) || (domain.agentkey.indexOf(req.query.key) == -1))) { return; } // If agent key is required and not provided or not valid, just hold the websocket and do nothing. + try { obj.meshAgentHandler.CreateMeshAgent(obj, obj.db, ws, req, obj.args, domain); } catch (e) { console.log(e); } + }); - // Handle all incoming requests as web relays - obj.webRelayRouter.options('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + // Setup mesh relay on alternative agent-only port + obj.agentapp.ws(url + 'meshrelay.ashx', function (ws, req) { + PerformWSSessionAuth(ws, req, true, function (ws1, req1, domain, user, cookie, authData) { + if (((parent.config.settings.desktopmultiplex === true) || (domain.desktopmultiplex === true)) && (req.query.p == 2)) { + obj.meshDesktopMultiplexHandler.CreateMeshRelay(obj, ws1, req1, domain, user, cookie); // Desktop multiplexor 1-to-n + } else { + obj.meshRelayHandler.CreateMeshRelay(obj, ws1, req1, domain, user, cookie); // Normal relay 1-to-1 + } + }); + }); - // Handle all incoming requests as web relays - obj.webRelayRouter.head('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + // Allows agents to transfer files + obj.agentapp.ws(url + 'devicefile.ashx', function (ws, req) { obj.meshDeviceFileHandler.CreateMeshDeviceFile(obj, ws, null, req, domain); }); + + // Setup agent to/from server file transfer handler + obj.agentapp.ws(url + 'agenttransfer.ashx', handleAgentFileTransfer); // Setup agent to/from server file transfer handler + + // Setup agent downloads for meshcore updates + obj.agentapp.get(url + 'meshagents', obj.handleMeshAgentRequest); + + // Setup agent file downloads + obj.agentapp.get(url + 'agentdownload.ashx', handleAgentDownloadFile); + } + + // Setup web relay on this web server if needed + // We set this up when a DNS name is used as a web relay instead of a port + if (obj.args.relaydns != null) { + obj.webRelayRouter = require('express').Router(); + + // This is the magic URL that will setup the relay session + obj.webRelayRouter.get('/control-redirect.ashx', function (req, res, next) { + if (obj.args.relaydns.indexOf(req.hostname) == -1) { res.sendStatus(404); return; } + if ((req.session.userid == null) && obj.args.user && obj.users['user//' + obj.args.user.toLowerCase()]) { req.session.userid = 'user//' + obj.args.user.toLowerCase(); } // Use a default user if needed + res.set({ 'Cache-Control': 'no-store' }); + parent.debug('web', 'webRelaySetup'); + + // Decode the relay cookie + if (req.query.c == null) { res.sendStatus(404); return; } + + // Decode and check if this relay cookie is valid + var userid, domainid, domain, nodeid, addr, port, appid, webSessionId, expire, publicid; + const urlCookie = obj.parent.decodeCookie(req.query.c, parent.loginCookieEncryptionKey, 32); // Allow cookies up to 32 minutes old. The web page will renew this cookie every 30 minutes. + if (urlCookie == null) { res.sendStatus(404); return; } + + // Decode the incoming cookie + if ((urlCookie.ruserid != null) && (urlCookie.x != null)) { + if (parent.webserver.destroyedSessions[urlCookie.ruserid + '/' + urlCookie.x] != null) { res.sendStatus(404); return; } + + // This is a standard user, figure out what our web relay will be. + if (req.session.x != urlCookie.x) { req.session.x = urlCookie.x; } // Set the sessionid if missing + if (req.session.userid != urlCookie.ruserid) { req.session.userid = urlCookie.ruserid; } // Set the session userid if missing + if (req.session.z) { delete req.session.z; } // Clear the web relay guest session + userid = req.session.userid; + domainid = userid.split('/')[1]; + domain = parent.config.domains[domainid]; + nodeid = ((req.query.relayid != null) ? req.query.relayid : req.query.n); + addr = (req.query.addr != null) ? req.query.addr : '127.0.0.1'; + port = parseInt(req.query.p); + appid = parseInt(req.query.appid); + webSessionId = req.session.userid + '/' + req.session.x; + + // Check that all the required arguments are present + if ((req.session.userid == null) || (req.session.x == null) || (req.query.n == null) || (req.query.p == null) || (parent.webserver.destroyedSessions[webSessionId] != null) || ((req.query.appid != 1) && (req.query.appid != 2))) { res.redirect('/'); return; } + } else if (urlCookie.r == 8) { + // This is a guest user, figure out what our web relay will be. + userid = urlCookie.userid; + domainid = userid.split('/')[1]; + domain = parent.config.domains[domainid]; + nodeid = urlCookie.nid; + addr = (urlCookie.addr != null) ? urlCookie.addr : '127.0.0.1'; + port = urlCookie.port; + appid = (urlCookie.p == 16) ? 2 : 1; // appid: 1 = HTTP, 2 = HTTPS + webSessionId = userid + '/' + urlCookie.pid; + publicid = urlCookie.pid; + if (req.session.x) { delete req.session.x; } // Clear the web relay sessionid + if (req.session.userid) { delete req.session.userid; } // Clear the web relay userid + if (req.session.z != webSessionId) { req.session.z = webSessionId; } // Set the web relay guest session + expire = urlCookie.expire; + if ((expire != null) && (expire <= Date.now())) { parent.debug('webrelay', 'expired link'); res.sendStatus(404); return; } + } + + // No session identifier was setup, exit now + if (webSessionId == null) { res.sendStatus(404); return; } + + // Check that we have an exact session on any of the relay DNS names + var xrelaySessionId, xrelaySession, freeRelayHost, oldestRelayTime, oldestRelayHost; + for (var hostIndex in obj.args.relaydns) { + const host = obj.args.relaydns[hostIndex]; + xrelaySessionId = webSessionId + '/' + host; + xrelaySession = webRelaySessions[xrelaySessionId]; + if (xrelaySession == null) { + // We found an unused hostname, save this as it could be useful. + if (freeRelayHost == null) { freeRelayHost = host; } + } else { + // Check if we already have a relay session that matches exactly what we want + if ((xrelaySession.domain.id == domain.id) && (xrelaySession.userid == userid) && (xrelaySession.nodeid == nodeid) && (xrelaySession.addr == addr) && (xrelaySession.port == port) && (xrelaySession.appid == appid)) { + // We found an exact match, we are all setup already, redirect to root of that DNS name + if (host == req.hostname) { + // Request was made on the same host, redirect to root. + res.redirect('/'); + } else { + // Request was made to a different host + const httpport = ((args.aliasport != null) ? args.aliasport : args.port); + res.redirect('https://' + host + ((httpport != 443) ? (':' + httpport) : '') + '/'); + } + return; + } + + // Keep a record of the oldest web relay session, this could be useful. + if (oldestRelayHost == null) { + // Oldest host not set yet, set it + oldestRelayHost = host; + oldestRelayTime = xrelaySession.lastOperation; + } else { + // Check if this host is older then oldest so far + if (oldestRelayTime > xrelaySession.lastOperation) { + oldestRelayHost = host; + oldestRelayTime = xrelaySession.lastOperation; + } + } + } + } + + // Check that the user has rights to access this device + parent.webserver.GetNodeWithRights(domain, userid, nodeid, function (node, rights, visible) { + // If there is no remote control or relay rights, reject this web relay + if ((rights & 0x00200008) == 0) { res.sendStatus(404); return; } // MESHRIGHT_REMOTECONTROL or MESHRIGHT_RELAY + + // Check if there is a free relay DNS name we can use + var selectedHost = null; + if (freeRelayHost != null) { + // There is a free one, use it. + selectedHost = freeRelayHost; + } else { + // No free ones, close the oldest one + selectedHost = oldestRelayHost; + } + xrelaySessionId = webSessionId + '/' + selectedHost; + + if (selectedHost == req.hostname) { + // If this web relay session id is not free, close it now + xrelaySession = webRelaySessions[xrelaySessionId]; + if (xrelaySession != null) { xrelaySession.close(); delete webRelaySessions[xrelaySessionId]; } + + // Create a web relay session + const relaySession = require('./apprelays.js').CreateWebRelaySession(obj, db, req, args, domain, userid, nodeid, addr, port, appid, xrelaySessionId, expire, node.mtype); + relaySession.xpublicid = publicid; + relaySession.onclose = function (sessionId) { + // Remove the relay session + delete webRelaySessions[sessionId]; + // If there are not more relay sessions, clear the cleanup timer + if ((Object.keys(webRelaySessions).length == 0) && (obj.cleanupTimer != null)) { clearInterval(webRelayCleanupTimer); obj.cleanupTimer = null; } + } + + // Set the multi-tunnel session + webRelaySessions[xrelaySessionId] = relaySession; + + // Setup the cleanup timer if needed + if (obj.cleanupTimer == null) { webRelayCleanupTimer = setInterval(checkWebRelaySessionsTimeout, 10000); } + + // Redirect to root. + res.redirect('/'); + } else { + if (req.query.noredirect != null) { + // No redirects allowed, fail here. This is important to make sure there is no redirect cascades + res.sendStatus(404); + } else { + // Request was made to a different host, redirect using the full URL so an HTTP cookie can be created on the other DNS name. + const httpport = ((args.aliasport != null) ? args.aliasport : args.port); + res.redirect('https://' + selectedHost + ((httpport != 443) ? (':' + httpport) : '') + req.url + '&noredirect=1'); + } + } + }); + }); + + // Handle all incoming requests as web relays + obj.webRelayRouter.get('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + + // Handle all incoming requests as web relays + obj.webRelayRouter.post('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + + // Handle all incoming requests as web relays + obj.webRelayRouter.put('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + + // Handle all incoming requests as web relays + obj.webRelayRouter.delete('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + + // Handle all incoming requests as web relays + obj.webRelayRouter.options('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + + // Handle all incoming requests as web relays + obj.webRelayRouter.head('/*', function (req, res) { try { handleWebRelayRequest(req, res); } catch (ex) { console.log(ex); } }) + } + + // Indicates to ExpressJS that the override public folder should be used to serve static files. + obj.app.use(url, function(req, res, next){ + var domain = getDomain(req); + if (domain.webpublicpath != null) { // Use domain public path + obj.express.static(domain.webpublicpath)(req, res, next); + } else if (obj.parent.webPublicOverridePath != null) { // Use override path + obj.express.static(obj.parent.webPublicOverridePath)(req, res, next); + } else { // carry on and use default public path + next(); + } + }); + // Indicates to ExpressJS that the default public folder should be used to serve static files. + obj.app.use(url, obj.express.static(obj.parent.webPublicPath)); + + // Start regular disconnection list flush every 2 minutes. + obj.wsagentsDisconnectionsTimer = setInterval(function () { obj.wsagentsDisconnections = {}; }, 120000); + } + } + function finalizeWebserver() { + // Setup all HTTP handlers + setupHTTPHandlers() + + // Handle 404 error + if (obj.args.nice404 !== false) { + obj.app.use(function (req, res, next) { + parent.debug('web', '404 Error ' + req.url); + var domain = getDomain(req); + if ((domain == null) || (domain.auth == 'sspi')) { res.sendStatus(404); return; } + if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL + const cspNonce = obj.crypto.randomBytes(15).toString('base64'); + res.set({ 'Content-Security-Policy': "default-src 'none'; script-src 'self' 'nonce-" + cspNonce + "'; img-src 'self'; style-src 'self' 'nonce-" + cspNonce + "';" }); // This page supports very tight CSP policy + res.status(404).render(getRenderPage((domain.sitestyle >= 2) ? 'error4042' : 'error404', req, domain), getRenderArgs({ cspNonce: cspNonce }, req, domain)); + }); } - // Indicates to ExpressJS that the override public folder should be used to serve static files. - if (parent.config.domains[i].webpublicpath != null) { - // Use domain public path - obj.app.use(url, obj.express.static(parent.config.domains[i].webpublicpath)); - } else if (obj.parent.webPublicOverridePath != null) { - // Use override path - obj.app.use(url, obj.express.static(obj.parent.webPublicOverridePath)); - } + // Start server on a free port. + CheckListenPort(obj.args.port, obj.args.portbind, StartWebServer); - // Indicates to ExpressJS that the default public folder should be used to serve static files. - obj.app.use(url, obj.express.static(obj.parent.webPublicPath)); + // Start on a second agent-only alternative port if needed. + if (obj.args.agentport) { CheckListenPort(obj.args.agentport, obj.args.agentportbind, StartAltWebServer); } - // Start regular disconnection list flush every 2 minutes. - obj.wsagentsDisconnectionsTimer = setInterval(function () { obj.wsagentsDisconnections = {}; }, 120000); + // We are done starting the web server. + if (doneFunc) doneFunc(); } + } - // Handle 404 error - if (obj.args.nice404 !== false) { - obj.app.use(function (req, res, next) { - parent.debug('web', '404 Error ' + req.url); - var domain = getDomain(req); - if ((domain == null) || (domain.auth == 'sspi')) { res.sendStatus(404); return; } - if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL - const cspNonce = obj.crypto.randomBytes(15).toString('base64'); - res.set({ 'Content-Security-Policy': "default-src 'none'; script-src 'self' 'nonce-" + cspNonce + "'; img-src 'self'; style-src 'self' 'nonce-" + cspNonce + "';" }); // This page supports very tight CSP policy - res.status(404).render(getRenderPage((domain.sitestyle == 2) ? 'error4042' : 'error404', req, domain), getRenderArgs({ cspNonce: cspNonce }, req, domain)); - }); - } - - // Start server on a free port. - CheckListenPort(obj.args.port, obj.args.portbind, StartWebServer); - - // Start on a second agent-only alternative port if needed. - if (obj.args.agentport) { CheckListenPort(obj.args.agentport, obj.args.agentportbind, StartAltWebServer); } - - // We are done starting the web server. - if (doneFunc) doneFunc(); + function nice404(req, res) { + parent.debug('web', '404 Error ' + req.url); + var domain = getDomain(req); + if ((domain == null) || (domain.auth == 'sspi')) { res.sendStatus(404); return; } + if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL + if (obj.args.nice404 == false) { res.sendStatus(404); return; } + const cspNonce = obj.crypto.randomBytes(15).toString('base64'); + res.set({ 'Content-Security-Policy': "default-src 'none'; script-src 'self' 'nonce-" + cspNonce + "'; img-src 'self'; style-src 'self' 'nonce-" + cspNonce + "';" }); // This page supports very tight CSP policy + res.status(404).render(getRenderPage((domain.sitestyle >= 2) ? 'error4042' : 'error404', req, domain), getRenderArgs({ cspNonce: cspNonce }, req, domain)); } // Auth strategy flags @@ -6958,7 +7456,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF twitter: 1, google: 2, github: 3, - reddit: 8, + reddit: 8, // Deprecated azure: 16, oidc: 32, saml: 64, @@ -6967,28 +7465,29 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } // Setup auth strategies for a domain - function setupDomainAuthStrategy(domain) { - // Return the auth strategies that have been setup - var authStrategyFlags = 0; + async function setupDomainAuthStrategy(domain) { + // Return binary flags representing all auth strategies that have been setup + let authStrategyFlags = 0; // Setup auth strategies using passport if needed if (typeof domain.authstrategies != 'object') return authStrategyFlags; - const url = domain.url; + const url = domain.url const passport = domain.passport = require('passport'); passport.serializeUser(function (user, done) { done(null, user.sid); }); passport.deserializeUser(function (sid, done) { done(null, { sid: sid }); }); obj.app.use(passport.initialize()); + obj.app.use(require('connect-flash')()); // Twitter if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) { const TwitterStrategy = require('passport-twitter'); - var options = { consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret }; + let options = { consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret }; if (typeof domain.authstrategies.twitter.callbackurl == 'string') { options.callbackURL = domain.authstrategies.twitter.callbackurl; } else { options.callbackURL = url + 'auth-twitter-callback'; } - parent.debug('authlog', 'Adding Twitter SSO with options: ' + JSON.stringify(options)); + parent.authLog('setupDomainAuthStrategy', 'Adding Twitter SSO with options: ' + JSON.stringify(options)); passport.use('twitter-' + domain.id, new TwitterStrategy(options, function (token, tokenSecret, profile, cb) { - parent.debug('authlog', 'Twitter profile: ' + JSON.stringify(profile)); + parent.authLog('setupDomainAuthStrategy', 'Twitter profile: ' + JSON.stringify(profile)); var user = { sid: '~twitter:' + profile.id, name: profile.displayName, strategy: 'twitter' }; if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } return cb(null, user); @@ -7000,12 +7499,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Google if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) { const GoogleStrategy = require('passport-google-oauth20'); - var options = { clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret }; + let options = { clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret }; if (typeof domain.authstrategies.google.callbackurl == 'string') { options.callbackURL = domain.authstrategies.google.callbackurl; } else { options.callbackURL = url + 'auth-google-callback'; } - parent.debug('authlog', 'Adding Google SSO with options: ' + JSON.stringify(options)); + parent.authLog('setupDomainAuthStrategy', 'Adding Google SSO with options: ' + JSON.stringify(options)); passport.use('google-' + domain.id, new GoogleStrategy(options, function (token, tokenSecret, profile, cb) { - parent.debug('authlog', 'Google profile: ' + JSON.stringify(profile)); + parent.authLog('setupDomainAuthStrategy', 'Google profile: ' + JSON.stringify(profile)); var user = { sid: '~google:' + profile.id, name: profile.displayName, strategy: 'google' }; if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string') && (profile.emails[0].verified == true)) { user.email = profile.emails[0].value; } return cb(null, user); @@ -7017,12 +7516,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Github if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) { const GitHubStrategy = require('passport-github2'); - var options = { clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret }; + let options = { clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret }; if (typeof domain.authstrategies.github.callbackurl == 'string') { options.callbackURL = domain.authstrategies.github.callbackurl; } else { options.callbackURL = url + 'auth-github-callback'; } - parent.debug('authlog', 'Adding Github SSO with options: ' + JSON.stringify(options)); + parent.authLog('setupDomainAuthStrategy', 'Adding Github SSO with options: ' + JSON.stringify(options)); passport.use('github-' + domain.id, new GitHubStrategy(options, function (token, tokenSecret, profile, cb) { - parent.debug('authlog', 'Github profile: ' + JSON.stringify(profile)); + parent.authLog('setupDomainAuthStrategy', 'Github profile: ' + JSON.stringify(profile)); var user = { sid: '~github:' + profile.id, name: profile.displayName, strategy: 'github' }; if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } return cb(null, user); @@ -7031,34 +7530,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF authStrategyFlags |= domainAuthStrategyConsts.github; } - // Reddit - if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) { - const RedditStrategy = require('passport-reddit'); - var options = { clientID: domain.authstrategies.reddit.clientid, clientSecret: domain.authstrategies.reddit.clientsecret }; - if (typeof domain.authstrategies.reddit.callbackurl == 'string') { options.callbackURL = domain.authstrategies.reddit.callbackurl; } else { options.callbackURL = url + 'auth-reddit-callback'; } - parent.debug('authlog', 'Adding Reddit SSO with options: ' + JSON.stringify(options)); - passport.use('reddit-' + domain.id, new RedditStrategy.Strategy(options, - function (token, tokenSecret, profile, cb) { - parent.debug('authlog', 'Reddit profile: ' + JSON.stringify(profile)); - var user = { sid: '~reddit:' + profile.id, name: profile.name, strategy: 'reddit' }; - if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } - return cb(null, user); - } - )); - authStrategyFlags |= domainAuthStrategyConsts.reddit; - } - // Azure if ((typeof domain.authstrategies.azure == 'object') && (typeof domain.authstrategies.azure.clientid == 'string') && (typeof domain.authstrategies.azure.clientsecret == 'string')) { const AzureOAuth2Strategy = require('passport-azure-oauth2'); - var options = { clientID: domain.authstrategies.azure.clientid, clientSecret: domain.authstrategies.azure.clientsecret, tenant: domain.authstrategies.azure.tenantid }; + let options = { clientID: domain.authstrategies.azure.clientid, clientSecret: domain.authstrategies.azure.clientsecret, tenant: domain.authstrategies.azure.tenantid }; if (typeof domain.authstrategies.azure.callbackurl == 'string') { options.callbackURL = domain.authstrategies.azure.callbackurl; } else { options.callbackURL = url + 'auth-azure-callback'; } - parent.debug('authlog', 'Adding Azure SSO with options: ' + JSON.stringify(options)); + parent.authLog('setupDomainAuthStrategy', 'Adding Azure SSO with options: ' + JSON.stringify(options)); passport.use('azure-' + domain.id, new AzureOAuth2Strategy(options, function (accessToken, refreshtoken, params, profile, done) { var userex = null; try { userex = require('jwt-simple').decode(params.id_token, '', true); } catch (ex) { } - parent.debug('authlog', 'Azure profile: ' + JSON.stringify(userex)); + parent.authLog('setupDomainAuthStrategy', 'Azure profile: ' + JSON.stringify(userex)); var user = null; if (userex != null) { var user = { sid: '~azure:' + userex.unique_name, name: userex.name, strategy: 'azure' }; @@ -7070,72 +7552,38 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF authStrategyFlags |= domainAuthStrategyConsts.azure; } - // Generic OpenID Connect - if ((typeof domain.authstrategies.oidc == 'object') && (typeof domain.authstrategies.oidc.clientid == 'string') && (typeof domain.authstrategies.oidc.clientsecret == 'string') && (typeof domain.authstrategies.oidc.issuer == 'string')) { - const OIDCStrategy = require('@mstrhakr/passport-openidconnect'); - const options = { - issuer: domain.authstrategies.oidc.issuer, - clientID: domain.authstrategies.oidc.clientid, - clientSecret: domain.authstrategies.oidc.clientsecret, - scope: ['profile', 'email'], - }; - const discoverOptions = async function(options){ - if ((typeof domain.authstrategies.oidc.authorizationurl != 'string') || (typeof domain.authstrategies.oidc.tokenurl != 'string') || (typeof domain.authstrategies.oidc.userinfourl != 'string')) { - const Issuer = require('openid-client').Issuer; - parent.debug('authlog', `OIDC: Attempting to discover well known endpoints for ${options.issuer}`); - var issuer = await Issuer.discover(options.issuer) - if (typeof domain.authstrategies.oidc.authorizationurl == 'string') { options.authorizationURL = domain.authstrategies.oidc.authorizationurl; } else { options.authorizationURL = issuer.metadata.authorization_endpoint; } - if (typeof domain.authstrategies.oidc.tokenurl == 'string') { options.tokenURL = domain.authstrategies.oidc.tokenurl; } else { options.tokenURL = issuer.metadata.token_endpoint; } - if (typeof domain.authstrategies.oidc.userinfourl == 'string') { options.userInfoURL = domain.authstrategies.oidc.userinfourl; } else { options.userInfoURL = issuer.metadata.userinfo_endpoint; } - if (typeof domain.authstrategies.oidc.callbackurl == 'string') { options.callbackURL = domain.authstrategies.oidc.callbackurl; } else { options.callbackURL = url + 'oidc-callback'; } - parent.debug('authlog', 'OIDC: Discovered: ' + JSON.stringify(options, null, 4)); - } - return options; - } - if (typeof domain.authstrategies.oidc.groups == 'object') { options.scope.push('groups') } - discoverOptions(options).then(function(options) { - passport.use('oidc-' + domain.id, new OIDCStrategy.Strategy(options, - function verify(issuer, profile, verified) { - parent.debug('authlog', `OIDC: Connecting to ${issuer} with the following options ` + JSON.stringify(options, null, 4)); - var user = { sid: '~oidc:' + profile.id, name: profile.displayName, strategy: 'oidc' }; - if (typeof profile.emails == 'object') { if (typeof profile.emails[0].value == 'string') { user.email = profile.emails[0].value; } else { user.email = profile.emails[0].value[0]; } } else if (typeof profile.emails == 'string') { user.email = profile.emails; } - if (options.scope.indexOf('groups') >= 0) { if ( Array.isArray(profile.groups[0].value) ) { user.groups = profile.groups[0].value; } else { user.groups = [profile.groups[0].value]; } } - parent.debug('authlog', `oidc: Configured:\nUser: ${JSON.stringify(user, null, 4)}\nFROM\nProfile: ${JSON.stringify(profile, null, 4)}`); - return verified(null, user); - } - )) - }); - authStrategyFlags |= domainAuthStrategyConsts.oidc; - } - // Generic SAML if (typeof domain.authstrategies.saml == 'object') { if ((typeof domain.authstrategies.saml.cert != 'string') || (typeof domain.authstrategies.saml.idpurl != 'string')) { - console.log('ERROR: Missing SAML configuration.'); + parent.debug('error', 'Missing SAML configuration.'); } else { const certPath = obj.common.joinPath(obj.parent.datapath, domain.authstrategies.saml.cert); var cert = obj.fs.readFileSync(certPath); if (cert == null) { - console.log('ERROR: Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert); + parent.debug('error', 'Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert); } else { var options = { entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral' }; if (typeof domain.authstrategies.saml.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.saml.callbackurl; } else { options.callbackUrl = url + 'auth-saml-callback'; } if (domain.authstrategies.saml.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.saml.disablerequestedauthncontext; } if (typeof domain.authstrategies.saml.entityid == 'string') { options.issuer = domain.authstrategies.saml.entityid; } - parent.debug('authlog', 'Adding SAML SSO with options: ' + JSON.stringify(options, null, 4)); + parent.authLog('setupDomainAuthStrategy', 'Adding SAML SSO with options: ' + JSON.stringify(options)); options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); const SamlStrategy = require('passport-saml').Strategy; passport.use('saml-' + domain.id, new SamlStrategy(options, function (profile, done) { - parent.debug('authlog', 'SAML profile: ' + JSON.stringify(profile, null, 4)); + parent.authLog('setupDomainAuthStrategy', 'SAML profile: ' + JSON.stringify(profile)); if (typeof profile.nameID != 'string') { return done(); } var user = { sid: '~saml:' + profile.nameID, name: profile.nameID, strategy: 'saml' }; - if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } + if (typeof profile.displayname == 'string') { + user.name = profile.displayname; + } else if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { + user.name = profile.firstname + ' ' + profile.lastname; + } if (typeof profile.email == 'string') { user.email = profile.email; } return done(null, user); } )); - authStrategyFlags |= domainAuthStrategyConsts.saml; + authStrategyFlags |= domainAuthStrategyConsts.saml } } } @@ -7143,22 +7591,22 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Intel SAML if (typeof domain.authstrategies.intel == 'object') { if ((typeof domain.authstrategies.intel.cert != 'string') || (typeof domain.authstrategies.intel.idpurl != 'string')) { - console.log('ERROR: Missing Intel SAML configuration.'); + parent.debug('error', 'Missing Intel SAML configuration.'); } else { var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.intel.cert)); if (cert == null) { - console.log('ERROR: Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert); + parent.debug('error', 'Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert); } else { var options = { entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral' }; if (typeof domain.authstrategies.intel.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.intel.callbackurl; } else { options.callbackUrl = url + 'auth-intel-callback'; } if (domain.authstrategies.intel.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.intel.disablerequestedauthncontext; } if (typeof domain.authstrategies.intel.entityid == 'string') { options.issuer = domain.authstrategies.intel.entityid; } - parent.debug('authlog', 'Adding Intel SSO with options: ' + JSON.stringify(options, null, 4)); + parent.authLog('setupDomainAuthStrategy', 'Adding Intel SSO with options: ' + JSON.stringify(options)); options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); const SamlStrategy = require('passport-saml').Strategy; passport.use('isaml-' + domain.id, new SamlStrategy(options, function (profile, done) { - parent.debug('authlog', 'Intel profile: ' + JSON.stringify(profile, null, 4)); + parent.authLog('setupDomainAuthStrategy', 'Intel profile: ' + JSON.stringify(profile)); if (typeof profile.nameID != 'string') { return done(); } var user = { sid: '~intel:' + profile.nameID, name: profile.nameID, strategy: 'intel' }; if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } @@ -7168,7 +7616,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF return done(null, user); } )); - authStrategyFlags |= domainAuthStrategyConsts.intelSaml; + authStrategyFlags |= domainAuthStrategyConsts.intelSaml } } } @@ -7176,21 +7624,21 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // JumpCloud SAML if (typeof domain.authstrategies.jumpcloud == 'object') { if ((typeof domain.authstrategies.jumpcloud.cert != 'string') || (typeof domain.authstrategies.jumpcloud.idpurl != 'string')) { - console.log('ERROR: Missing JumpCloud SAML configuration.'); + parent.debug('error', 'Missing JumpCloud SAML configuration.'); } else { var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.jumpcloud.cert)); if (cert == null) { - console.log('ERROR: Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert); + parent.debug('error', 'Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert); } else { var options = { entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral' }; if (typeof domain.authstrategies.jumpcloud.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.jumpcloud.callbackurl; } else { options.callbackUrl = url + 'auth-jumpcloud-callback'; } if (typeof domain.authstrategies.jumpcloud.entityid == 'string') { options.issuer = domain.authstrategies.jumpcloud.entityid; } - parent.debug('authlog', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options, null, 4)); + parent.authLog('setupDomainAuthStrategy', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options)); options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); const SamlStrategy = require('passport-saml').Strategy; passport.use('jumpcloud-' + domain.id, new SamlStrategy(options, function (profile, done) { - parent.debug('authlog', 'JumpCloud profile: ' + JSON.stringify(profile, null, 4)); + parent.authLog('setupDomainAuthStrategy', 'JumpCloud profile: ' + JSON.stringify(profile)); if (typeof profile.nameID != 'string') { return done(); } var user = { sid: '~jumpcloud:' + profile.nameID, name: profile.nameID, strategy: 'jumpcloud' }; if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } @@ -7198,11 +7646,290 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF return done(null, user); } )); - authStrategyFlags |= domainAuthStrategyConsts.jumpCloudSaml; + authStrategyFlags |= domainAuthStrategyConsts.jumpCloudSaml } } } + // Setup OpenID Connect Authentication Strategy + if (obj.common.validateObject(domain.authstrategies.oidc)) { + parent.authLog('setupDomainAuthStrategy', `OIDC: Setting up strategy for domain: ${domain.id == null ? 'default' : domain.id}`); + // Ensure required objects exist + let initStrategy = domain.authstrategies.oidc + if (typeof initStrategy.issuer == 'string') { initStrategy.issuer = { 'issuer': initStrategy.issuer } } + let strategy = migrateOldConfigs(Object.assign({ 'client': {}, 'issuer': {}, 'options': {}, 'custom': {}, 'obj': { 'openidClient': require('openid-client') } }, initStrategy)) + let preset = obj.common.validateString(strategy.custom.preset) ? strategy.custom.preset : null + if (!preset) { + if (typeof strategy.custom.tenant_id == 'string') { strategy.custom.preset = preset = 'azure' } + if (strategy.custom.customer_id || strategy.custom.identitysource || strategy.client.client_id.split('.')[2] == 'googleusercontent') { strategy.custom.preset = preset = 'google' } + } + + // Check issuer url + let presetIssuer + if (preset == 'azure') { presetIssuer = 'https://login.microsoftonline.com/' + strategy.custom.tenant_id + '/v2.0'; } + if (preset == 'google') { presetIssuer = 'https://accounts.google.com'; } + if (!obj.common.validateString(strategy.issuer.issuer)) { + if (!preset) { + let error = new Error('OIDC: Missing issuer URI.'); + parent.authLog('error', `${error.message} STRATEGY: ${JSON.stringify(strategy)}`); + throw error; + } else { + strategy.issuer.issuer = presetIssuer + parent.authLog('setupDomainAuthStrategy', `OIDC: PRESET: ${preset.toUpperCase()}: Using preset issuer: ${presetIssuer}`); + } + } else if ((typeof strategy.issuer.issuer == 'string') && (typeof strategy.custom.preset == 'string')) { + let error = new Error(`OIDC: PRESET: ${strategy.custom.preset.toUpperCase()}: PRESET OVERRIDDEN: CONFIG ISSUER: ${strategy.issuer.issuer} PRESET ISSUER: ${presetIssuer}`); + parent.authLog('setupDomainAuthStrategy', error.message); + console.warn(error) + } + + // Setup Strategy Options + strategy.custom.scope = obj.common.convertStrArray(strategy.custom.scope, ' ') + if (strategy.custom.scope.length > 1) { + strategy.options = Object.assign(strategy.options, { 'params': { 'scope': strategy.custom.scope } }) + } else { + strategy.options = Object.assign(strategy.options, { 'params': { 'scope': ['openid', 'profile', 'email'] } }) + } + if (typeof strategy.groups == 'object') { + let groupScope = strategy.groups.scope || null + if (groupScope == null) { + if (preset == 'azure') { groupScope = 'Group.Read.All' } + if (preset == 'google') { groupScope = 'https://www.googleapis.com/auth/cloud-identity.groups.readonly' } + if (typeof preset != 'string') { groupScope = 'groups' } + } + strategy.options.params.scope.push(groupScope) + } + strategy.options.params.scope = strategy.options.params.scope.join(' ') + + // Discover additional information if available, use endpoints from config if present + let issuer + try { + parent.authLog('setupDomainAuthStrategy', `OIDC: Discovering Issuer Endpoints: ${strategy.issuer.issuer}`); + issuer = await strategy.obj.openidClient.Issuer.discover(strategy.issuer.issuer); + } catch (err) { + let error = new Error('OIDC: Discovery failed.', { cause: err }); + parent.authLog('setupDomainAuthStrategy', `ERROR: ${JSON.stringify(error)} ISSUER_URI: ${strategy.issuer.issuer}`); + throw error + } + if (Object.keys(strategy.issuer).length > 1) { + parent.authLog('setupDomainAuthStrategy', `OIDC: Adding Issuer Metadata: ${JSON.stringify(strategy.issuer)}`); + issuer = new strategy.obj.openidClient.Issuer(Object.assign(issuer?.metadata, strategy.issuer)); + } + strategy.issuer = issuer?.metadata; + strategy.obj.issuer = issuer; + + var httpport = ((args.aliasport != null) ? args.aliasport : args.port); + var origin = 'https://' + (domain.dns ? domain.dns : parent.certificates.CommonName); + if (httpport != 443) { origin += ':' + httpport; } + + // Make sure redirect_uri and post_logout_redirect_uri exist before continuing + if (!strategy.client.redirect_uri) { + strategy.client.redirect_uri = origin + url + 'auth-oidc-callback'; + } + if (!strategy.client.post_logout_redirect_uri) { + strategy.client.post_logout_redirect_uri = origin + url + 'login'; + } + + // Create client and overwrite in options + let client = new issuer.Client(strategy.client) + strategy.options = Object.assign(strategy.options, { 'client': client, sessionKey: 'oidc-' + domain.id }); + strategy.client = client.metadata + strategy.obj.client = client + + // Setup strategy and save configs for later + passport.use('oidc-' + domain.id, new strategy.obj.openidClient.Strategy(strategy.options, oidcCallback)); + parent.config.domains[domain.id].authstrategies.oidc = strategy; + parent.debug('verbose', 'OIDC: Saved Configuration: ' + JSON.stringify(strategy)); + if (preset) { parent.authLog('setupDomainAuthStrategy', 'OIDC: ' + preset.toUpperCase() + ': Setup Complete'); } + else { parent.authLog('setupDomainAuthStrategy', 'OIDC: Setup Complete'); } + + authStrategyFlags |= domainAuthStrategyConsts.oidc + + function migrateOldConfigs(strategy) { + let oldConfigs = { + 'client': { + 'clientid': 'client_id', + 'clientsecret': 'client_secret', + 'callbackurl': 'redirect_uri' + }, + 'issuer': { + 'authorizationurl': 'authorization_endpoint', + 'tokenurl': 'token_endpoint', + 'userinfourl': 'userinfo_endpoint' + }, + 'custom': { + 'tenantid': 'tenant_id', + 'customerid': 'customer_id' + } + } + for (var type in oldConfigs) { + for (const [key, value] of Object.entries(oldConfigs[type])) { + if (Object.hasOwn(strategy, key)) { + if (strategy[type][value] && obj.common.validateString(strategy[type][value])) { + let error = new Error('OIDC: OLD CONFIG: Config conflict, new config overrides old config'); + parent.authLog('migrateOldConfigs', `${JSON.stringify(error)} OLD CONFIG: ${key}: ${strategy[key]} NEW CONFIG: ${value}:${strategy[type][value]}`); + } else { + parent.authLog('migrateOldConfigs', `OIDC: OLD CONFIG: Moving old config to new location. strategy.${key} => strategy.${type}.${value}`); + strategy[type][value] = strategy[key]; + } + delete strategy[key] + } + } + } + if (typeof strategy.scope == 'string') { + if (!strategy.custom.scope) { + strategy.custom.scope = strategy.scope; + strategy.options.params = { 'scope': strategy.scope }; + parent.authLog('migrateOldConfigs', `OIDC: OLD CONFIG: Moving old config to new location. strategy.scope => strategy.custom.scope`); + } else { + let error = new Error('OIDC: OLD CONFIG: Config conflict, using new config values.'); + parent.authLog('migrateOldConfigs', `${error.message} OLD CONFIG: strategy.scope: ${strategy.scope} NEW CONFIG: strategy.custom.scope:${strategy.custom.scope}`); + parent.debug('warning', error.message) + } + delete strategy.scope + } + if (strategy.groups && strategy.groups.sync && strategy.groups.sync.enabled && strategy.groups.sync.enabled === true) { + if (strategy.groups.sync.filter) { + delete strategy.groups.sync.enabled; + } else { + strategy.groups.sync = true; + } + parent.authLog('migrateOldConfigs', `OIDC: OLD CONFIG: Moving old config to new location. strategy.groups.sync.enabled => strategy.groups.sync`); + } + return strategy + } + + // Callback function must be able to grab info from API's using the access token, would prefer to use the token here. + function oidcCallback(tokenset, profile, verified) { + // Initialize user object + let user = { 'strategy': 'oidc' } + let claims = obj.common.validateObject(strategy.custom.claims) ? strategy.custom.claims : null; + user.sid = obj.common.validateString(profile.sub) ? '~oidc:' + profile.sub : null; + user.name = obj.common.validateString(profile.name) ? profile.name : null; + user.email = obj.common.validateString(profile.email) ? profile.email : null; + if (claims != null) { + user.sid = obj.common.validateString(profile[claims.uuid]) ? '~oidc:' + profile[claims.uuid] : user.sid; + user.name = obj.common.validateString(profile[claims.name]) ? profile[claims.name] : user.name; + user.email = obj.common.validateString(profile[claims.email]) ? profile[claims.email] : user.email; + } + user.emailVerified = profile.email_verified ? profile.email_verified : obj.common.validateEmail(user.email); + user.groups = obj.common.validateStrArray(profile.groups, 1) ? profile.groups : null; + user.preset = obj.common.validateString(strategy.custom.preset) ? strategy.custom.preset : null; + if (strategy.groups && obj.common.validateString(strategy.groups.claim)) { + user.groups = obj.common.validateStrArray(profile[strategy.groups.claim], 1) ? profile[strategy.groups.claim] : null + } + + // Setup end session enpoint if not already configured this requires an auth token + try { + if (!strategy.issuer.end_session_endpoint) { + strategy.issuer.end_session_endpoint = strategy.obj.client.endSessionUrl({ 'id_token_hint': tokenset }) + parent.authLog('oidcCallback', `OIDC: Discovered end_session_endpoint: ${strategy.issuer.end_session_endpoint}`); + } + } catch (err) { + let error = new Error('OIDC: Discovering end_session_endpoint failed. Using Default.', { cause: err }); + strategy.issuer.end_session_endpoint = strategy.issuer.issuer + '/logout'; + parent.debug('error', `${error.message} end_session_endpoint: ${strategy.issuer.end_session_endpoint} post_logout_redirect_uri: ${strategy.client.post_logout_redirect_uri} TOKENSET: ${JSON.stringify(tokenset)}`); + parent.authLog('oidcCallback', error.message); + } + + // Setup presets and groups, get groups from API if needed then return + if (strategy.groups && typeof user.preset == 'string') { + getGroups(user.preset, tokenset).then((groups) => { + user = Object.assign(user, { 'groups': groups }); + return verified(null, user); + }).catch((err) => { + let error = new Error('OIDC: GROUPS: No groups found due to error:', { cause: err }); + parent.debug('error', `${JSON.stringify(error)}`); + parent.authLog('oidcCallback', error.message); + user.groups = []; + return verified(null, user); + }); + } else { + return verified(null, user); + } + + async function getGroups(preset, tokenset) { + let url = ''; + if (preset == 'azure') { url = strategy.groups.recursive == true ? 'https://graph.microsoft.com/v1.0/me/transitiveMemberOf?$top=999' : 'https://graph.microsoft.com/v1.0/me/memberOf?$top=999'; } + if (preset == 'google') { url = strategy.custom.customer_id ? 'https://cloudidentity.googleapis.com/v1/groups?parent=customers/' + strategy.custom.customer_id : strategy.custom.identitysource ? 'https://cloudidentity.googleapis.com/v1/groups?parent=identitysources/' + strategy.custom.identitysource : null; } + return new Promise((resolve, reject) => { + const options = { + 'headers': { authorization: 'Bearer ' + tokenset.access_token } + } + const req = require('https').get(url, options, (res) => { + let data = [] + res.on('data', (chunk) => { + data.push(chunk); + }); + res.on('end', () => { + if (res.statusCode < 200 || res.statusCode >= 300) { + let error = new Error('OIDC: GROUPS: Bad response code from API, statusCode: ' + res.statusCode); + parent.authLog('getGroups', `ERROR: ${error.message} URL: ${url} OPTIONS: ${JSON.stringify(options)}`); + console.error(error); + reject(error); + } + if (data.length == 0) { + let error = new Error('OIDC: GROUPS: Getting groups from API failed, request returned no data in response.'); + parent.authLog('getGroups', `ERROR: ${error.message} URL: ${url} OPTIONS: ${JSON.stringify(options)}`); + console.error(error); + reject(error); + } + try { + if (Buffer.isBuffer(data[0])) { + data = Buffer.concat(data); + data = data.toString(); + } else { // else if (typeof data[0] == 'string') + data = data.join(); + } + } catch (err) { + let error = new Error('OIDC: GROUPS: Getting groups from API failed. Error joining response data.', { cause: err }); + parent.authLog('getGroups', `ERROR: ${error.message} URL: ${url} OPTIONS: ${JSON.stringify(options)}`); + console.error(error); + reject(error); + } + if (preset == 'azure') { + data = JSON.parse(data); + if (data.error) { + let error = new Error('OIDC: GROUPS: Getting groups from API failed. Error joining response data.', { cause: data.error }); + parent.authLog('getGroups', `ERROR: ${error.message} URL: ${url} OPTIONS: ${JSON.stringify(options)}`); + console.error(error); + reject(error); + } + data = data.value; + } + if (preset == 'google') { + data = data.split('\n'); + data = data.join(''); + data = JSON.parse(data); + data = data.groups; + } + let groups = [] + for (var i in data) { + if (typeof data[i].displayName == 'string') { + groups.push(data[i].displayName); + } + } + if (groups.length == 0) { + let warn = new Error('OIDC: GROUPS: No groups returned from API.'); + parent.authLog('getGroups', `WARN: ${warn.message} DATA: ${data}`); + console.warn(warn); + resolve(groups); + } else { + resolve(groups); + } + }); + }); + req.on('error', (err) => { + let error = new Error('OIDC: GROUPS: Request error.', { cause: err }); + parent.authLog('getGroups', `ERROR: ${error.message} URL: ${url} OPTIONS: ${JSON.stringify(options)}`); + console.error(error); + reject(error); + }); + req.end(); + }); + } + } + } return authStrategyFlags; } @@ -7521,6 +8248,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF parent.debug('web', 'Invalid login, asking for email validation'); try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, email2fasent: true })); ws.close(); } catch (e) { } } else { + req.session.userid = user._id; + req.session.ip = req.clientIp; + setSessionRandom(req); func(ws, req, domain, user, null, authData); } } @@ -7536,6 +8266,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, sms2fa: sms2fa, msg2fa: msg2fa, email2fasent: true })); ws.close(); } catch (e) { } } else { // We are authenticated + req.session.userid = user._id; + req.session.ip = req.clientIp; + setSessionRandom(req); func(ws, req, domain, user); } } @@ -7664,7 +8397,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (emailcheck && (user.email != null) && (!(user._id.split('/')[2].startsWith('~'))) && (user.emailVerified !== true)) { parent.debug('web', 'Invalid login, asking for email validation'); try { ws.send(JSON.stringify({ action: 'close', cause: 'emailvalidation', msg: 'emailvalidationrequired', email2fa: email2fa, email2fasent: true })); ws.close(); } catch (e) { } - } else { + } else { + req.session.userid = user._id; + req.session.ip = req.clientIp; + setSessionRandom(req); func(ws, req, domain, user); } } @@ -7730,7 +8466,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF }); obj.parent.updateServerState('servername', certificates.CommonName); } - obj.parent.authLog('https', 'Server listening on ' + ((addr != null) ? addr : '0.0.0.0') + ' port ' + port + '.'); + obj.parent.debug('https', 'Server listening on ' + ((addr != null) ? addr : '0.0.0.0') + ' port ' + port + '.'); obj.parent.updateServerState('https-port', port); if (args.aliasport != null) { obj.parent.updateServerState('https-aliasport', args.aliasport); } } else { @@ -7760,14 +8496,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF function StartAltWebServer(port, addr) { if ((port < 1) || (port > 65535)) return; var agentAliasPort = null; + var agentAliasDns = null; if (args.agentaliasport != null) { agentAliasPort = args.agentaliasport; } + if (args.agentaliasdns != null) { agentAliasDns = args.agentaliasdns; } if (obj.tlsAltServer != null) { if (obj.args.lanonly == true) { obj.tcpAltServer = obj.tlsAltServer.listen(port, addr, function () { console.log('MeshCentral HTTPS agent-only server running on port ' + port + ((agentAliasPort != null) ? (', alias port ' + agentAliasPort) : '') + '.'); }); } else { - obj.tcpAltServer = obj.tlsAltServer.listen(port, addr, function () { console.log('MeshCentral HTTPS agent-only server running on ' + certificates.CommonName + ':' + port + ((agentAliasPort != null) ? (', alias port ' + agentAliasPort) : '') + '.'); }); + obj.tcpAltServer = obj.tlsAltServer.listen(port, addr, function () { console.log('MeshCentral HTTPS agent-only server running on ' + ((agentAliasDns != null) ? agentAliasDns : certificates.CommonName) + ':' + port + ((agentAliasPort != null) ? (', alias port ' + agentAliasPort) : '') + '.'); }); } - obj.parent.authLog('https', 'Server listening on 0.0.0.0 port ' + port + '.'); + obj.parent.debug('https', 'Server listening on 0.0.0.0 port ' + port + '.'); obj.parent.updateServerState('https-agent-port', port); } else { obj.tcpAltServer = obj.agentapp.listen(port, addr, function () { console.log('MeshCentral HTTP agent-only server running on port ' + port + ((agentAliasPort != null) ? (', alias port ' + agentAliasPort) : '') + '.'); }); @@ -7922,9 +8660,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } }; - // - // Access Control Functions - // + /* Access Control Functions */ // Remove user rights function removeUserRights(rights, user) { @@ -8263,6 +8999,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF delete user2.otpsms; delete user2.otpmsg; if ((typeof user2.otpekey == 'object') && (user2.otpekey != null)) { user2.otpekey = 1; } // Indicates that email 2FA is enabled. + if ((typeof user2.otpduo == 'object') && (user2.otpduo != null)) { user2.otpduo = 1; } // Indicates that duo 2FA is enabled. if ((typeof user2.otpsecret == 'string') && (user2.otpsecret != null)) { user2.otpsecret = 1; } // Indicates a time secret is present. if ((typeof user2.otpkeys == 'object') && (user2.otpkeys != null)) { user2.otpkeys = 0; if (user.otpkeys != null) { for (var i = 0; i < user.otpkeys.keys.length; i++) { if (user.otpkeys.keys[i].u == true) { user2.otpkeys = 1; } } } } // Indicates the number of one time backup codes that are active. if ((typeof user2.otphkeys == 'object') && (user2.otphkeys != null)) { user2.otphkeys = user2.otphkeys.length; } // Indicates the number of hardware keys setup @@ -8318,8 +9055,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } // Filter the user web site and only output state that we need to keep - const acceptableUserWebStateStrings = ['webPageStackMenu', 'notifications', 'deviceView', 'nightMode', 'webPageFullScreen', 'search', 'showRealNames', 'sort', 'deskAspectRatio', 'viewsize', 'DeskControl', 'uiMode', 'footerBar']; - const acceptableUserWebStateDesktopStrings = ['encoding', 'showfocus', 'showmouse', 'showcad', 'limitFrameRate', 'noMouseRotate', 'quality', 'scaling'] + const acceptableUserWebStateStrings = ['webPageStackMenu', 'notifications', 'deviceView', 'nightMode', 'webPageFullScreen', 'search', 'showRealNames', 'sort', 'deskAspectRatio', 'viewsize', 'DeskControl', 'uiMode', 'footerBar','loctag','theme','lastThemes','uiViewMode']; + const acceptableUserWebStateDesktopStrings = ['encoding', 'showfocus', 'showmouse', 'showcad', 'limitFrameRate', 'noMouseRotate', 'quality', 'scaling', 'agentencoding'] obj.filterUserWebState = function (state) { if (typeof state == 'string') { try { state = JSON.parse(state); } catch (ex) { return null; } } if ((state == null) || (typeof state != 'object')) { return null; } @@ -8423,7 +9160,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } xargs.extitle = encodeURIComponent(xargs.title).split('\'').join('\\\''); xargs.domainurl = domain.url; - xargs.autocomplete = (domain.autocomplete === false) ? 'x' : 'autocomplete'; // This option allows autocomplete to be turned off on the login page. + xargs.autocomplete = (domain.autocomplete === false) ? 'autocomplete=off x' : 'autocomplete'; // This option allows autocomplete to be turned off on the login page. if (typeof domain.hide == 'number') { xargs.hide = domain.hide; } // To mitigate any possible BREACH attack, we generate a random 0 to 255 bytes length string here. @@ -8534,9 +9271,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (obj.renderPages != null) { // Get the list of acceptable languages in order var acceptLanguages = obj.getLanguageCodes(req); - + var domain = getDomain(req); // Take a look at the options we have for this file - var fileOptions = obj.renderPages[obj.path.basename(filename)]; + var fileOptions = obj.renderPages[domain.id][obj.path.basename(filename)]; if (fileOptions != null) { for (var i in acceptLanguages) { if ((acceptLanguages[i] == 'en') || (acceptLanguages[i].startsWith('en-'))) { @@ -8583,36 +9320,58 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (translateFolder != null) { obj.renderPages = {}; obj.renderLanguages = ['en']; - var files = obj.fs.readdirSync(translateFolder); - for (var i in files) { - var name = files[i]; - if (name.endsWith('.handlebars')) { - name = name.substring(0, name.length - 11); - var xname = name.split('_'); - if (xname.length == 2) { - if (obj.renderPages[xname[0]] == null) { obj.renderPages[xname[0]] = {}; } - obj.renderPages[xname[0]][xname[1]] = obj.path.join(translateFolder, name); - if (obj.renderLanguages.indexOf(xname[1]) == -1) { obj.renderLanguages.push(xname[1]); } - } - } - } - - // See if there are any custom rending pages that will override the default ones - if ((obj.parent.webViewsOverridePath != null) && (obj.fs.existsSync(obj.path.join(obj.parent.webViewsOverridePath, 'translations')))) { - translateFolder = obj.path.join(obj.parent.webViewsOverridePath, 'translations'); + for (var i in parent.config.domains) { + if (obj.fs.existsSync('views/translations')) { translateFolder = 'views/translations'; } + if (obj.fs.existsSync(obj.path.join(__dirname, 'views', 'translations'))) { translateFolder = obj.path.join(__dirname, 'views', 'translations'); } var files = obj.fs.readdirSync(translateFolder); + var domain = parent.config.domains[i].id; + obj.renderPages[domain] = {}; for (var i in files) { var name = files[i]; if (name.endsWith('.handlebars')) { name = name.substring(0, name.length - 11); var xname = name.split('_'); if (xname.length == 2) { - if (obj.renderPages[xname[0]] == null) { obj.renderPages[xname[0]] = {}; } - obj.renderPages[xname[0]][xname[1]] = obj.path.join(translateFolder, name); + if (obj.renderPages[domain][xname[0]] == null) { obj.renderPages[domain][xname[0]] = {}; } + obj.renderPages[domain][xname[0]][xname[1]] = obj.path.join(translateFolder, name); if (obj.renderLanguages.indexOf(xname[1]) == -1) { obj.renderLanguages.push(xname[1]); } } } } + // See if there are any custom rending pages that will override the default ones + if ((obj.parent.webViewsOverridePath != null) && (obj.fs.existsSync(obj.path.join(obj.parent.webViewsOverridePath, 'translations')))) { + translateFolder = obj.path.join(obj.parent.webViewsOverridePath, 'translations'); + var files = obj.fs.readdirSync(translateFolder); + for (var i in files) { + var name = files[i]; + if (name.endsWith('.handlebars')) { + name = name.substring(0, name.length - 11); + var xname = name.split('_'); + if (xname.length == 2) { + if (obj.renderPages[domain][xname[0]] == null) { obj.renderPages[domain][xname[0]] = {}; } + obj.renderPages[domain][xname[0]][xname[1]] = obj.path.join(translateFolder, name); + if (obj.renderLanguages.indexOf(xname[1]) == -1) { obj.renderLanguages.push(xname[1]); } + } + } + } + } + // See if there is a custom meshcentral-web-domain folder as that will override the default ones + if (obj.fs.existsSync(obj.path.join(__dirname, '..', 'meshcentral-web-' + domain, 'views', 'translations'))) { + translateFolder = obj.path.join(__dirname, '..', 'meshcentral-web-' + domain, 'views', 'translations'); + var files = obj.fs.readdirSync(translateFolder); + for (var i in files) { + var name = files[i]; + if (name.endsWith('.handlebars')) { + name = name.substring(0, name.length - 11); + var xname = name.split('_'); + if (xname.length == 2) { + if (obj.renderPages[domain][xname[0]] == null) { obj.renderPages[domain][xname[0]] = {}; } + obj.renderPages[domain][xname[0]][xname[1]] = obj.path.join(translateFolder, name); + if (obj.renderLanguages.indexOf(xname[1]) == -1) { obj.renderLanguages.push(xname[1]); } + } + } + } + } } } } @@ -8698,7 +9457,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } - // Insure exclusivity of a push messaging token for Android device + // Ensure exclusivity of a push messaging token for Android device obj.removePmtFromAllOtherNodes = function (node) { if (typeof node.pmt != 'string') return; db.Get('pmt_' + node.pmt, function (err, docs) { @@ -8734,7 +9493,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } // Return decoded user agent information - obj.getUserAgentInfo = function(req) { + obj.getUserAgentInfo = function (req) { var browser = 'Unknown', os = 'Unknown'; try { const ua = obj.uaparser((typeof req == 'string') ? req : req.headers['user-agent']); @@ -8744,8 +9503,27 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF } catch (ex) { return { browserStr: browser, osStr: os } } } - // Return the query string portion of the URL, the ? and anything after. - function getQueryPortion(req) { var s = req.url.indexOf('?'); if (s == -1) { if (req.body && req.body.urlargs) { return req.body.urlargs; } return ''; } return req.url.substring(s); } + // Return the query string portion of the URL, the ? and anything after BUT remove secret keys from authentication providers + function getQueryPortion(req) { + var removeKeys = ['duo_code', 'state']; // Keys to remove + var s = req.url.indexOf('?'); + if (s == -1) { + if (req.body && req.body.urlargs) { + return req.body.urlargs; + } + return ''; + } + var queryString = req.url.substring(s + 1); + var params = queryString.split('&'); + var filteredParams = []; + for (var i = 0; i < params.length; i++) { + var key = params[i].split('=')[0]; + if (removeKeys.indexOf(key) === -1) { + filteredParams.push(params[i]); + } + } + return (filteredParams.length > 0 ? ('?' + filteredParams.join('&')) : ''); + } // Generate a random Intel AMT password function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); } @@ -9059,7 +9837,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF parent.DispatchEvent(['*', ugrpid, user._id], obj, event); // Even if DB change stream is active, this event must be acted upon. // Log in the auth log - parent.authLog('https', 'Created ' + userMembershipType + ' user group ' + ugrp.name); + parent.authLog('https', userMembershipType.toUpperCase() + ': Created user group ' + ugrp.name); } if (existingUserMemberships[ugrpid] == null) { @@ -9086,7 +9864,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF parent.DispatchEvent(['*', ugrp._id, user._id], obj, event); // Log in the auth log - parent.authLog('https', 'Adding ' + user.name + ' to ' + userMembershipType + ' user group ' + userMemberships[i] + '.'); + parent.authLog('https', userMembershipType.toUpperCase() + ': Adding ' + user.name + ' to user group ' + userMemberships[i] + '.'); } else { // User is already part of this user group delete existingUserMemberships[ugrpid]; @@ -9096,7 +9874,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF // Remove the user from any memberships they don't belong to anymore for (var ugrpid in existingUserMemberships) { var ugrp = obj.userGroups[ugrpid]; - parent.authLog('https', 'Removing ' + user.name + ' from ' + userMembershipType + ' user group ' + ugrp.name + '.'); + parent.authLog('https', userMembershipType.toUpperCase() + ': Removing ' + user.name + ' from user group ' + ugrp.name + '.'); if ((user.links != null) && (user.links[ugrpid] != null)) { delete user.links[ugrpid];